<?php
/**
 * Service_Booking
 *
 * Класс Service_Booking осуществляет работу с API сайта Booking.com
 *
 * @author Egorov Aleksandr (slamer86@gmail.com)
 */
class Service_Booking {	
	public $rows = 1000; // Кол-во запрашиваемых записей
	public $offset = null; // Начиная с какой записи возвращать
	public $lastChange = null; // Время последнего изменения
	public $showTest = 0; // Показывать ли тестовые отели
	public $arrCountryCodes = array(); // Массив кодов стран
	public $arrLanguageCodes = array(); // Массив кодов языков
	public $arrFields = array(); // Массив с полями которые должен вернуть букинг
	public $arrCityIds = array(); // Массив ID городов
	public $arrDistrictIds = array(); // Массив ID районов
	public $arrRegionIds = array(); // Массив ID регионов
	public $arrCreditCardIds = array(); // Массив ID кредитных карт
	public $arrChainIds = array(); // Массив ID сетей отелей
	public $arrClasses = array(); // Массив с звездностью отелей
	public $arrHotelIds = array(); // Массив ID отелей
	public $arrDescriptionTypeIds = array(); // Массив ID типов описаний
	public $arrFacilityTypeIds = array(); // Массив ID типов услуг
	public $arrHotelFacilityTypeIds = array(); // Массив ID типов услуг отеля
	public $arrTypes = array(); // Массив типов данных, которые возвращать (Реально никаких кроме bool нет)
	public $arrRoomTypeIds = array(); // Массив ID типов номеров
	public $arrRoomIds = array(); // Массив ID номеров
	public $arrRoomFacilityTypeIds = array(); // Массив ID типов услуг номеров
	public $test = 1;	// Флаг работаем ли мы в тестовом режиме
	public $_arrSystemLang = array('en', 'ru'); // Массив языков которые используются в системе
	private $_arrSecureFunctions = array('processBooking', 'cancelBooking', 'getBookingDetails'); 

	/**
	 * Получаем адрес для вызова API
	 * 
	 * @param string $functionName - Название функции
	 * @param bool $https - Флаг, нужно ли использовать SSL
	 */
	public function getBookingPath($functionName, $https = false) {
		return 'http' . ($https ? 's' : '') . '://' . BOOKING_LOGIN . ':' . BOOKING_PASS . '@' . (in_array($functionName, $this->_arrSecureFunctions) ? 'secure-' : '') . 'distribution-xml.booking.com/xml/bookings.' . $functionName;
	}

	/**
	 * Обрабатываем результат от букинга
	 * 
	 * @param array $arrResult - Массив с результатом букинга
	 */
	private function _processResult(array $arrResult) {
		Service_Debug::setDebug();
		if (isset($arrResult['fault'])) { // Если есть ошибки, то сохраняем их и возвращаем результат 
			return $arrResult;
		}
		if (!isset($arrResult['result'])) return array();
		if (!isset($arrResult['result'][0])) return array($arrResult['result']);
		else return $arrResult['result'];
	}

	/**
	 * Получаем страны
	 *
	 * @return array - Массив данных
	 */
	public function getCountries() {
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getCountries'), array(
			'countrycodes' => $this->arrCountryCodes, 
			'languagecodes' => $this->arrLanguageCodes, 
			'rows' => $this->rows, 
			'offset' => $this->offset
		));
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Получаем и сохраняем страны
	 */
	public function parseCountries() {
		$objDB = Service_Database::instance();
		foreach ($this->_arrSystemLang as $lang) {
			$this->arrLanguageCodes = array($lang);
			$arrCountries = $this->getCountries();
			if (empty($arrCountries) || isset($arrCountries['fault'])) continue;
			foreach ($arrCountries as $arrCountry) {
				$stmt = "INSERT INTO country (country_code, area_" . $lang . ", country_name_" . $lang . ") 
								 VALUES ('" . $arrCountry['countrycode'] . "', '" . $arrCountry['area'] . "', '" . $arrCountry['name'] . "')
								 ON DUPLICATE KEY UPDATE 
								 country_name_" . $lang . " = VALUES(country_name_" . $lang . ")";
				$objDB->query($stmt);
				$objCountry = new Country($arrCountry['countrycode']);
				$objCountry->updateCountryFinalName();
			}			
		}
		// Генерируем URL для стран у которых он пустой
		$stmt = "SELECT country.country_code, country.country_name_en FROM country WHERE country_url IS NULL";
		$arrCountries = $objDB->select($stmt);
		foreach ($arrCountries as $arrCountry) {
			$countryUrl = Service_Generate::generateAlias($arrCountry['country_name_en']);
			$stmt = "UPDATE country 
			SET country.country_url = '" . $countryUrl . "'
			WHERE country.country_code = '" . $arrCountry['country_code'] . "'";
			$objDB->query($stmt);
			$stmt = "UPDATE city 
			SET city.country_url = '" . $countryUrl . "'
			WHERE city.country_code = '" . $arrCountry['country_code'] . "'";
			$objDB->query($stmt);	
			$stmt = "UPDATE hotel 
			SET hotel.country_url = '" . $countryUrl . "'
			WHERE hotel.country_code = '" . $arrCountry['country_code'] . "'";			
			$objDB->query($stmt);
		}
	}	
	
	/**
	 * Получаем города
	 *
	 * @return array - Массив данных
	 */
	public function getCities() {
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getCities'), array(
			'city_ids' => $this->arrCityIds,
			'countrycodes' => $this->arrCountryCodes, 
			'fields' => $this->arrFields, 
			'languagecodes' => $this->arrLanguageCodes, 
			'rows' => $this->rows, 
			'offset' => $this->offset
		));
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Получаем и сохраняем города
	 */
	public function parseCities() {
		Pressure::setStart();
		$objDB = Service_Database::instance();
		$stmt = "SELECT country_code FROM country ORDER BY last_parse, country_code";
		$arrCountryCodes = $objDB->selectSimpleArray($stmt);
		foreach ($arrCountryCodes as $countryCode) { // Проходим по странам 
			$this->arrCountryCodes = array($countryCode);
			foreach ($this->_arrSystemLang as $lang) { // Проходим по языкам
				$count = 0;
				$this->arrLanguageCodes = array($lang);
				do {
					$this->offset = $count;	
					$arrCities = $this->getCities();
					if (empty($arrCities) || isset($arrCities['fault'])) break;
					foreach ($arrCities as $arrCity) { // Проходим по полученным городам и сохраняем их
						$arrCity['name'] = Service_Escape::absolutelyEscapeString($arrCity['name']);
						$stmt = "INSERT INTO city (`ID_city`,`country_code`,`latitude`,`longitude`,`city_name_" . $lang . "`) 
										 VALUES ('" . $arrCity['city_id'] . "', '" . $arrCity['countrycode'] . "', '" . $arrCity['latitude'] . "', '" . $arrCity['longitude'] . "', '" . $arrCity['name'] . "')
										 ON DUPLICATE KEY UPDATE 
										 `city_name_" . $lang . "` = VALUES(`city_name_" . $lang . "`)";
						$objDB->query($stmt);		
						$objCity = new City($arrCity['city_id']);
						$objCity->updateCityFinalName();						
					}
					$count += sizeof($arrCities);
				}
				while (sizeof($arrCities) == $this->rows);
			}
			$objDB->update('country', array('last_parse' => Service_Date::gLocalTime2BD()), array('country_code' => $countryCode));
			$time = Pressure::calculateCurrentDuration();
			if ($time > 30) {
				// Генерируем URL для городов у которых он пустой
				$stmt = "SELECT city.ID_city, city.city_name_en FROM city WHERE city_url IS NULL";
				$arrCities = $objDB->select($stmt);
				foreach ($arrCities as $arrCity) { // Проходим по городам с пустым url и генерируем его
					$cityUrl = Service_Generate::generateAlias($arrCity['city_name_en']);
					$stmt = "UPDATE city 
					SET city.city_url = '" . $cityUrl . "'
					WHERE city.ID_city = '" . $arrCity['ID_city'] . "'";
					$objDB->query($stmt);
					$stmt = "UPDATE hotel 
					SET hotel.city_url = '" . $cityUrl . "'
					WHERE hotel.ID_city = '" . $arrCity['ID_city'] . "'";			
					$objDB->query($stmt);
				}
				return false;			
			}
		}
	}

	/**
	 * Получаем районы
	 *
	 * @return array - Массив данных
	 */
	public function getDistricts() {
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getDistricts'), array(
			'district_ids' => $this->arrDistrictIds, 
			'city_ids' => $this->arrCityIds, 
			'countrycodes' => $this->arrCountryCodes, 
			'fields' => $this->arrFields, 
			'languagecodes' => $this->arrLanguageCodes, 
			'rows' => $this->rows, 
			'offset' => $this->offset, 
			'last_change' => $this->lastChange
		));
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Получаем и сохраняем районы
	 */
	public function parseDistricts() {
		$objDB = Service_Database::instance();
		foreach ($this->_arrSystemLang as $lang) {
			$count = 0;
			$this->arrLanguageCodes = array($lang);		
			do {
				$this->offset = $count;	
				$arrDistricts = $this->getDistricts();
				if (empty($arrDistricts) || isset($arrDistricts['fault'])) break;
				foreach ($arrDistricts as $arrDistrict) {
					if (isset($arrDistrict['code'])) continue;
					$arrDistrict['name'] = Service_Escape::absolutelyEscapeString($arrDistrict['name']);
					$stmt = "INSERT INTO district (`ID_district`,`country_code`,`ID_city`,`district_name_" . $lang . "`) 
									 VALUES ('" . $arrDistrict['district_id'] . "', '" . $arrDistrict['countrycode'] . "', '" . $arrDistrict['city_id'] . "', '" . $arrDistrict['name'] . "')
									 ON DUPLICATE KEY UPDATE 
									 `district_name_" . $lang . "` = VALUES(`district_name_" . $lang . "`)";
					$objDB->query($stmt);
				}
				$count += sizeof($arrDistricts);
			}
			while (sizeof($arrDistricts) == $this->rows);
		}
	}	
	
	/**
	 * Получаем регионы
	 *
	 * @return array - Массив данных
	 */
	public function getRegions($arrRegionTypes = array()) {
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getRegions'), array(
			'region_ids' => $this->arrRegionIds,
			'region_types' => $arrRegionTypes, 
			'countrycodes' => $this->arrCountryCodes, 
			'fields' => $this->arrFields, 
			'languagecodes' => $this->arrLanguageCodes, 
			'rows' => $this->rows, 
			'offset' => $this->offset, 
			'last_change' => $this->lastChange			
		));
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Получаем и сохраняем регионы
	 */
	public function parseRegions() {
		$objDB = Service_Database::instance();
		foreach ($this->_arrSystemLang as $lang) {
			$count = 0;
			$this->arrLanguageCodes = array($lang);		
			do {			
				$this->offset = $count;	
				$arrRegions = $this->getRegions();	
				if (empty($arrRegions) || isset($arrRegions['fault'])) break;
				foreach ($arrRegions as $arrRegion) {					
					$arrRegion['name'] = Service_Escape::absolutelyEscapeString($arrRegion['name']);
					$stmt = "INSERT INTO region (`ID_region`,`country_code`,`region_type`,`region_name_" . $lang . "`) 
									 VALUES ('" . $arrRegion['region_id'] . "', '" . $arrRegion['countrycode'] . "', '" . $arrRegion['region_type'] . "', '" . $arrRegion['name'] . "')
									 ON DUPLICATE KEY UPDATE 
									 `region_name_" . $lang . "` = VALUES(`region_name_" . $lang . "`)";
					$objDB->query($stmt);
				}
				$count += sizeof($arrRegions);
			}
			while (sizeof($arrRegions) == $this->rows);
		}
	}		
	
	/**
	 * Получаем типы кредитных карт
	 *
	 * @return array - Массив данных
	 */
	public function getCreditCardTypes() {
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getCreditcardTypes'), array(
			'creditcard_ids' => $this->arrCreditCardIds, 
			'fields' => $this->arrFields
		));
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Получаем и сохраняем типы кредитных карт
	 */
	public function parseCreditCardTypes() {
		$objDB = Service_Database::instance();			
		$arrCreditCards = $this->getCreditCardTypes();
		if (empty($arrCreditCards) || isset($arrCreditCards['fault'])) return false;
		foreach ($arrCreditCards as $arrCreditCard) {
			$stmt = "INSERT INTO credit_card (`ID_credit_card`,`credit_card_name`,`is_bookable`) 
							 VALUES ('" . $arrCreditCard['creditcard_id'] . "', '" . $arrCreditCard['name'] . "', '" . $arrCreditCard['bookable'] . "')
							 ON DUPLICATE KEY
							 UPDATE 
							 `credit_card_name` = VALUES(`credit_card_name`),
							 `is_bookable` = VALUES(`is_bookable`)";
			$objDB->query($stmt);
		}
	}				
	
	/**
	 * Получаем типы кредитных карт
	 *
	 * @return array - Массив данных
	 */
	public function getCreditCards() {
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getCreditcards'), array(
			'creditcard_ids' => $this->arrCreditCardIds, 
			'city_ids' => $this->arrCityIds, 
			'classes' => $this->arrClasses, 
			'countrycodes' => $this->arrCountryCodes, 
			'fields' => $this->arrFields, 
			'hotel_ids' => $this->arrHotelIds, 
			'rows' => $this->rows, 
			'offset' => $this->offset, 
			'last_change' => $this->lastChange,
			'show_test' => $this->showTest,  
		));
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Получаем и сохраняем типы кредитных карт
	 */
	public function parseCreditCards() {
		$objDB = Service_Database::instance();			
		if (!empty($this->arrHotelIds)) {
			$stmt = "DELETE FROM hotel_credit_card WHERE ID_hotel IN (" . join(',', $this->arrHotelIds) . ")";
			$objDB->query($stmt);				
		}						
		$count = 0;
		do {			
			$this->offset = $count;	
			$arrCreditCards = $this->getCreditCards();
			if (empty($arrCreditCards) || isset($arrCreditCards['fault'])) break;
			foreach ($arrCreditCards as $arrCreditCard) {
				$stmt = "INSERT INTO hotel_credit_card (`ID_hotel`,`ID_credit_card`,`is_bookable`,`is_payable`) 
								 VALUES ('" . $arrCreditCard['hotel_id'] . "', '" . $arrCreditCard['creditcard_id'] . "', '" . $arrCreditCard['bookable'] . "', '" . $arrCreditCard['payable'] . "')
								 ON DUPLICATE KEY UPDATE 
								 `is_bookable` = VALUES(`is_bookable`),
								 `is_payable` = VALUES(`is_payable`)";
				$objDB->query($stmt);
			}
			$count += sizeof($arrCreditCards);
		}
		while (sizeof($arrCreditCards) == $this->rows);
	}			
	
	/**
	 * Получаем типы сетей гостиниц
	 *
	 * @return array - Массив данных
	 */
	public function getChainTypes() {
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getChainTypes'), array(
			'chain_ids' => $this->arrChainIds, 
			'fields' => $this->arrFields
		));
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Получаем и сохраняем типы кредитных карт
	 */
	public function parseChainTypes() {
		$objDB = Service_Database::instance();			
		$arrChainTypes = $this->getChainTypes();
		if (empty($arrChainTypes) || isset($arrChainTypes['fault'])) return false;
		foreach ($arrChainTypes as $arrChainType) {
			$arrChainType['name'] = Service_Escape::absolutelyEscapeString($arrChainType['name']);
			$stmt = "INSERT INTO chain (`ID_chain`,`chain_name`) 
							 VALUES ('" . $arrChainType['chain_id'] . "', '" . $arrChainType['name'] . "')
							 ON DUPLICATE KEY UPDATE 
							 `chain_name` = VALUES(`chain_name`)";
			$objDB->query($stmt);
		}
	}		

	/**
	 * Получаем связи гостиниц и сетей
	 *
	 * @return array - Массив данных
	 */
	public function getChains() {
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getChains'), array(
			'chain_ids' => $this->arrChainIds,
			'city_ids' => $this->arrCityIds, 
			'classes' => $this->arrClasses, 
			'countrycodes' => $this->arrCountryCodes, 
			'fields' => $this->arrFields, 
			'hotel_ids' => $this->arrHotelIds, 
			'rows' => $this->rows, 
			'offset' => $this->offset,
			'show_test' => $this->showTest,  
			'last_change' => $this->lastChange
		));
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Получаем и сохраняем связи отелей и сетей
	 */
	public function parseChains() {
		$objDB = Service_Database::instance();
		$count = 0;
		do {					
			$this->offset = $count;
			$arrChains = $this->getChains();
			if (empty($arrChains) || isset($arrChains['fault'])) break;
			foreach ($arrChains as $arrChain) {
				$stmt = "UPDATE hotel
								 SET ID_chain = '" . $arrChain['chain_id'] . "'
								 WHERE ID_hotel = '" . $arrChain['hotel_id'] . "'";
				$objDB->query($stmt);
			}
			$count += sizeof($arrChains);
		}
		while (sizeof($arrChains) == $this->rows);			
	}			
	
	/**
	 * Получаем связи гостиниц и регионов
	 *
	 * @return array - Массив данных
	 */
	public function getRegionHotels() {
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getRegionHotels'), array(
			'region_ids' => $this->arrRegionIds, 
			'classes' => $this->arrClasses, 
			'countrycodes' => $this->arrCountryCodes, 
			'fields' => $this->arrFields, 
			'hotel_ids' => $this->arrHotelIds, 
			'rows' => $this->rows, 
			'offset' => $this->offset, 
			'last_change' => $this->lastChange
		));
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Получаем и сохраняем связи гостиниц и регионов
	 */
	public function parseRegionHotels() {
		$objDB = Service_Database::instance();
		$count = 0;
		do {					
			$this->offset = $count;
			$arrRegionHotels = $this->getRegionHotels();		
			if (empty($arrRegionHotels) || isset($arrRegionHotels['fault'])) break;
			foreach ($arrRegionHotels as $arrRegionHotel) {
				$stmt = "UPDATE hotel
								 SET ID_region = '" . $arrRegionHotel['region_id'] . "'
								 WHERE ID_hotel = '" . $arrRegionHotel['hotel_id'] . "'";
				$objDB->query($stmt);
				usleep(10000);
			}
			$count += sizeof($arrRegionHotels);
		}
		while (sizeof($arrRegionHotels) == $this->rows);			
	}		
		
	/**
	 * Получаем связи гостиниц и районов
	 *
	 * @return array - Массив данных
	 */
	public function getDistrictHotels() {
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getDistrictHotels'), array(
			'city_ids' => $this->arrCityIds, 
			'district_ids' => $this->arrDistrictIds, 
			'classes' => $this->arrClasses, 
			'countrycodes' => $this->arrCountryCodes, 
			'fields' => $this->arrFields, 
			'hotel_ids' => $this->arrHotelIds, 
			'rows' => $this->rows, 
			'offset' => $this->offset,
		 	'show_test' => $this->showTest,
			'last_change' => $this->lastChange
		));
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Получаем и сохраняем связи гостиниц и районов
	 */
	public function parseDistrictHotels() {
		$objDB = Service_Database::instance();
		$count = 0;
		do {					
			$this->offset = $count;
			$arrDistrictHotels = $this->getDistrictHotels();
			if (empty($arrDistrictHotels) || isset($arrDistrictHotels['fault'])) break;
			foreach ($arrDistrictHotels as $arrDistrictHotel) {
				$stmt = "UPDATE hotel
								 SET ID_district = '" . $arrDistrictHotel['district_id'] . "'
								 WHERE ID_hotel = '" . $arrDistrictHotel['hotel_id'] . "'";
				$objDB->query($stmt);
			}
			$count += sizeof($arrDistrictHotels);
		}
		while (sizeof($arrDistrictHotels) == $this->rows);			
	}

	/**
	 * Получаем типы описаний отелей
	 *
	 * @return array - Массив данных
	 */
	public function getHotelDescriptionTypes() {
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getHotelDescriptionTypes'), array(
			'descriptiontype_ids' => $this->arrDescriptionTypeIds, 
			'languagecodes' => $this->arrLanguageCodes, 
			'fields' => $this->arrFields
		));
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Получаем и сохраняем типы описаний гостиниц
	 */
	public function parseHotelDescriptionTypes() {
		$objDB = Service_Database::instance();	
		foreach ($this->_arrSystemLang as $lang) {
			$this->arrLanguageCodes = array($lang);				
			$arrHotelDescriptionTypes = $this->getHotelDescriptionTypes();
			if (empty($arrHotelDescriptionTypes) || isset($arrHotelDescriptionTypes['fault'])) continue;
			foreach ($arrHotelDescriptionTypes as $arrHotelDescriptionType) {
				$arrHotelDescriptionType['name'] = Service_Escape::absolutelyEscapeString($arrHotelDescriptionType['name']);
				$stmt = "INSERT INTO description_type (`ID_description_type`,`description_type_name_" . $lang . "`) 
								 VALUES ('" . $arrHotelDescriptionType['descriptiontype_id'] . "', '" . $arrHotelDescriptionType['name'] . "')
								 ON DUPLICATE KEY UPDATE 
								 `description_type_name_" . $lang . "` = VALUES(`description_type_name_" . $lang . "`)";
				$objDB->query($stmt);
			}
		}
	}

	/**
	 * Получаем фотографии описания отелей
	 *
	 * @return array - Массив данных
	 */
	public function getHotelDescriptionPhotos() {
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getHotelDescriptionPhotos'), array(
			'hotel_ids' => $this->arrHotelIds, 
			'city_ids' => $this->arrCityIds, 
			'classes' => $this->arrClasses, 
			'countrycodes' => $this->arrCountryCodes, 
			'fields' => $this->arrFields,  
			'rows' => $this->rows,
			'offset' => $this->offset, 
			'show_test' => $this->showTest,
			'last_change' => $this->lastChange)
		);
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Получаем и сохраняем фотографии описания отелей
	 */
	public function parseHotelDescriptionPhotos() {
		$objDB = Service_Database::instance();
		if (!empty($this->arrHotelIds)) { // Если парсим для конкретных отелей, то удаляем все их фотки до добавления
			$stmt = "DELETE FROM hotel_description_photo WHERE ID_hotel IN (" . join(',', $this->arrHotelIds) . ")";
			$objDB->query($stmt);				
		}						
		$count = 0;
		do {			
			$this->offset = $count;	
			$arrHotelDescriptionPhotos = $this->getHotelDescriptionPhotos();
			if (empty($arrHotelDescriptionPhotos) || isset($arrHotelDescriptionPhotos['fault'])) break;
			foreach ($arrHotelDescriptionPhotos as $arrHotelDescriptionPhoto) {
				$arrHotelDescriptionPhoto['descriptiontype_id'] = empty($arrHotelDescriptionPhoto['descriptiontype_id']) ? 'null' : $arrHotelDescriptionPhoto['descriptiontype_id'];	
				$stmt = "INSERT INTO hotel_description_photo (`ID_photo`,`ID_hotel`,`ID_description_type`,`url_original`,`url_max_300`,`url_square_60`) 
								 VALUES ('" . $arrHotelDescriptionPhoto['photo_id'] . "', '" . $arrHotelDescriptionPhoto['hotel_id'] . "', " . $arrHotelDescriptionPhoto['descriptiontype_id'] . ", '" . $arrHotelDescriptionPhoto['url_original'] . "', '" . $arrHotelDescriptionPhoto['url_max300'] . "', '" . $arrHotelDescriptionPhoto['url_square60'] . "')
								 ON DUPLICATE KEY
								 UPDATE 
								 `ID_hotel` = VALUES(`ID_hotel`),
								 `ID_description_type` = VALUES(`ID_description_type`),
								 `url_original` = VALUES(`url_original`),
								 `url_max_300` = VALUES(`url_max_300`),
								 `url_square_60` = VALUES(`url_square_60`)
								 ";
				$objDB->query($stmt);
			}
			$count += sizeof($arrHotelDescriptionPhotos);	
		}
		while (sizeof($arrHotelDescriptionPhotos) == $this->rows);
	}

	/**
	 * Получаем описания отелей
	 *
	 * @return array - Массив данных
	 */
	public function getHotelDescriptions() {
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getHotelDescriptionTranslations'), array(
			'hotel_ids' => $this->arrHotelIds, 
			'city_ids' => $this->arrCityIds, 
			'classes' => $this->arrClasses, 
			'countrycodes' => $this->arrCountryCodes,
			'languagecodes' => $this->arrLanguageCodes, 
			'fields' => $this->arrFields, 
			'descriptiontype_ids' => $this->arrDescriptionTypeIds, 
			'rows' => $this->rows, 
			'offset' => $this->offset, 
			'show_test' => $this->showTest,		
			'last_change' => $this->lastChange)
		);
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Получаем и сохраняем описания отелей
	 */
	public function parseHotelDescriptions() {
		$objDB = Service_Database::instance();	
		if (!empty($this->arrHotelIds)) { // Если парсим для конкретных отелей, то удаляем все их описания до добавления
			$stmt = "DELETE FROM hotel_description WHERE ID_hotel IN (" . join(',', $this->arrHotelIds) . ")";
			$objDB->query($stmt);				
		}								
		foreach ($this->_arrSystemLang as $lang) {
			$count = 0;
			$this->arrLanguageCodes = array($lang);		
			do {			
				$this->offset = $count;	
				$arrHotelDescriptions = $this->getHotelDescriptions();
				if (empty($arrHotelDescriptions) || isset($arrHotelDescriptions['fault'])) break;
				foreach ($arrHotelDescriptions as $arrHotelDescription) {
					$arrHotelDescription['description'] = Service_Escape::absolutelyEscapeString($arrHotelDescription['description']);
					$stmt = "INSERT INTO hotel_description (`ID_hotel`,`ID_description_type`,`hotel_description_" . $lang . "`) 
									 VALUES ('" . $arrHotelDescription['hotel_id'] . "', '" . $arrHotelDescription['descriptiontype_id'] . "', '" . $arrHotelDescription['description'] . "')
									 ON DUPLICATE KEY UPDATE `hotel_description_" . $lang . "` = '" . $arrHotelDescription['description'] . "'";
					$objDB->query($stmt);
					if ($arrHotelDescription['descriptiontype_id'] == 6) {
						$stmt = "UPDATE `hotel` 
						  SET `xml_description_" . $lang . "` = '" . $arrHotelDescription['description'] . "'
						  WHERE `ID_hotel` = '" . $arrHotelDescription['hotel_id'] . "'";
						$objDB->query($stmt);
					} 
				}
				$count += sizeof($arrHotelDescriptions);
			}
			while (sizeof($arrHotelDescriptions) == $this->rows);
		}
	}		
	
	/**
	 * Получаем типы услуг
	 *
	 * @return array - Массив данных
	 */
	public function getFacilityTypes() {
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getFacilityTypes'), array(
			'facilitytype_ids' => $this->arrFacilityTypeIds, 
			'languagecodes' => $this->arrLanguageCodes, 
			'fields' => $this->arrFields
		));
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Получаем и сохраняем типы услуг
	 */
	public function parseFacilityTypes() {
		$objDB = Service_Database::instance();	
		foreach ($this->_arrSystemLang as $lang) {
			$this->arrLanguageCodes = array($lang);				
			$arrFaclilityTypes = $this->getFacilityTypes();
			if (empty($arrFaclilityTypes) || isset($arrFaclilityTypes['fault'])) continue;
			foreach ($arrFaclilityTypes as $arrFaclilityType) {
				$arrFaclilityType['name'] = Service_Escape::absolutelyEscapeString($arrFaclilityType['name']);
				$stmt = "INSERT INTO facility_type (`ID_facility_type`,`facility_type_name_" . $lang . "`) 
								 VALUES ('" . $arrFaclilityType['facilitytype_id'] . "', '" . $arrFaclilityType['name'] . "')
								 ON DUPLICATE KEY UPDATE 
								 `facility_type_name_" . $lang . "` = VALUES(`facility_type_name_" . $lang . "`)";
				$objDB->query($stmt);
			}
		}
	}

	/**
	 * Получаем типы услуг отелей
	 *
	 * @return array - Массив данных
	 */
	public function getHotelFacilityTypes() {
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getHotelFacilityTypes'), array(
			'facilitytype_ids' => $this->arrFacilityTypeIds,
			'hotelfacilitytype_ids' => $this->arrHotelFacilityTypeIds, 
			'fields' => $this->arrFields, 
			'languagecodes' => $this->arrLanguageCodes, 
			'types' => $this->arrTypes			
		));
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Получаем и сохраняем типы услуг отелей
	 */
	public function parseHotelFacilityTypes() {
		$objDB = Service_Database::instance();
		foreach ($this->_arrSystemLang as $lang) {
			$this->arrLanguageCodes = array($lang);		
			$arrHotelFacilityTypes = $this->getHotelFacilityTypes();
			if (empty($arrHotelFacilityTypes) || isset($arrHotelFacilityTypes['fault'])) continue;
			foreach ($arrHotelFacilityTypes as $arrHotelFacilityType) {
				$arrHotelFacilityType['name'] = Service_Escape::absolutelyEscapeString($arrHotelFacilityType['name']);
				$stmt = "INSERT INTO hotel_facility_type (`ID_hotel_facility_type`,`ID_facility_type`,`hotel_facility_type_name_" . $lang . "`,`hotel_facility_type_type`) 
								 VALUES ('" . $arrHotelFacilityType['hotelfacilitytype_id'] . "', '" . $arrHotelFacilityType['facilitytype_id'] . "', '" . $arrHotelFacilityType['name'] . "', '" . $arrHotelFacilityType['type'] . "')
								 ON DUPLICATE KEY UPDATE 
								 `hotel_facility_type_name_" . $lang . "` = VALUES(`hotel_facility_type_name_" . $lang . "`)";
				$objDB->query($stmt);
			}
		}
	}			
	
	/**
	 * Получаем услуги отелей
	 *
	 * @return array - Массив данных
	 */
	public function getHotelFacilities() {
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getHotelFacilities'), array(
			'city_ids' => $this->arrCityIds, 
			'classes' => $this->arrClasses, 
			'countrycodes' => $this->arrCountryCodes,
			'facilitytype_ids' => $this->arrFacilityTypeIds,
			'hotel_ids' => $this->arrHotelIds,  
			'hotelfacilitytype_ids' => $this->arrHotelFacilityTypeIds, 
			'fields' => $this->arrFields,  
			'rows' => $this->rows, 
			'offset' => $this->offset, 
			'show_test' => $this->showTest,		
			'last_change' => $this->lastChange
		));
		return $this->_processResult($arrResult);
	}

	/**
	 * Получаем и сохраняем услуги отелей
	 */
	public function parseHotelFacilities() {
		$objDB = Service_Database::instance();	
		if (!empty($this->arrHotelIds)) { // Если парсим для конкретных отелей, то удаляем все их услуги до добавления
			$stmt = "DELETE FROM hotel_facility WHERE ID_hotel IN (" . join(',', $this->arrHotelIds) . ")";
			$objDB->query($stmt);				
		}						
		$count = 0;
		do {			
			$this->offset = $count;	
			$arrHotelFacilities = $this->getHotelFacilities();
			if (empty($arrHotelFacilities) || isset($arrHotelFacilities['fault'])) break;
			foreach ($arrHotelFacilities as $arrHotelFacility) {
				$stmt = "INSERT INTO hotel_facility (`ID_facility_type`,`ID_hotel_facility_type`,`ID_hotel`,`value`) 
								 VALUES ('" . $arrHotelFacility['facilitytype_id'] . "', '" . $arrHotelFacility['hotelfacilitytype_id'] . "', '" . $arrHotelFacility['hotel_id'] . "', '" . $arrHotelFacility['value'] . "')
								 ON DUPLICATE KEY UPDATE 
								 `value` = VALUES(`value`)";
				$objDB->query($stmt);
			}
			$count += sizeof($arrHotelFacilities);			
		}
		while (sizeof($arrHotelFacilities) == $this->rows);
	}
	
	/**
	 * Получаем типы номеров
	 *
	 * @return array - Массив данных
	 */
	public function getRoomTypes() {
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getRoomTypes'), array(
			'fields' => $this->arrFields, 
			'languagecodes' => $this->arrLanguageCodes, 
			'roomtype_ids' => $this->arrRoomTypeIds			
		));
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Получаем и сохраняем типы номеров
	 */
	public function parseRoomTypes() {
		$objDB = Service_Database::instance();
		foreach ($this->_arrSystemLang as $lang) {
			$this->arrLanguageCodes = array($lang);		
			$arrRoomTypes = $this->getRoomTypes();
			if (empty($arrRoomTypes) || isset($arrRoomTypes['fault'])) continue;
			foreach ($arrRoomTypes as $arrRoomType) {
				$arrRoomType['name'] = Service_Escape::absolutelyEscapeString($arrRoomType['name']);
				$stmt = "INSERT INTO room_type (`ID_room_type`,`room_type_name_" . $lang . "`) 
								 VALUES ('" . $arrRoomType['roomtype_id'] . "', '" . $arrRoomType['name'] . "')
								 ON DUPLICATE KEY UPDATE 
								 `room_type_name_" . $lang . "` = VALUES(`room_type_name_" . $lang . "`)";
				$objDB->query($stmt);
			}
		}
	}		
	
	/**
	 * Получаем номера
	 *
	 * @return array - Массив данных
	 */
	public function getRooms($maxPersons = null, $roomSize = 1, $showConfiguration = 1) {
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getRooms'), array(
			'city_ids' => $this->arrCityIds, 
			'classes' => $this->arrClasses, 
			'countrycodes' => $this->arrCountryCodes,
			'fields' => $this->arrFields,
			'hotel_ids' => $this->arrHotelIds,			
			'max_persons' => $maxPersons,
			'room_ids' => $this->arrRoomIds,
			'roomtype_ids' => $this->arrRoomTypeIds,	  
			'rows' => $this->rows, 
			'offset' => $this->offset, 
			'show_test' => $this->showTest,
			'last_change' => $this->lastChange,
			'show_room_size' => $roomSize,
			'show_configuration' => $showConfiguration		
		));
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Получаем и сохраняем номера
	 */
	public function parseRooms() {
		$objDB = Service_Database::instance();				
		$count = 0;
		do {			
			$this->offset = $count;	
			$arrRooms = $this->getRooms();
			if (empty($arrRooms) || isset($arrRooms['fault'])) break;
			foreach ($arrRooms as $key => $arrRoom) {
				$stmt = "INSERT INTO room (`ID_room`,`ID_hotel`,`ID_room_type`,`max_persons`,`min_price`,`max_price`,`room_rank`,`room_size`)
								 VALUES ('" . $arrRoom['room_id'] . "', '" . $arrRoom['hotel_id'] . "', '" . $arrRoom['roomtype_id'] . "', '" . $arrRoom['max_persons'] . "', '" . $arrRoom['min_price'] . "', '" . $arrRoom['max_price'] . "', '" . $arrRoom['ranking'] . "', '" . intval($arrRoom['room_size']) . "')
								 ON DUPLICATE KEY UPDATE 
								 ID_hotel = VALUES(ID_hotel),
								 ID_room_type = VALUES(ID_room_type),
								 max_persons = VALUES(max_persons),
								 min_price = VALUES(min_price),
								 max_price = VALUES(max_price),
								 room_rank = VALUES(room_rank),
								 room_size = VALUES(room_size)";
				$objDB->query($stmt);
				// Сохраняем кровати
				if (isset($arrRoom['bedding'])) {
					if (isset($arrRoom['bedding']['beds'][0])) $arrBeds = $arrRoom['bedding']['beds'];
					else $arrBeds = array($arrRoom['bedding']['beds']);
					$stmt = "DELETE FROM room_bed WHERE ID_room = '" . $arrRoom['room_id'] . "'";
					$objDB->query($stmt);
					foreach ($arrBeds as $arrBed) {
						$stmt = "INSERT IGNORE INTO room_bed (`ID_room`,`beds_amount`,`beds_type`,`beds_configuration`)
										 VALUES ('" . $arrRoom['room_id'] . "', '" . $arrBed['amount'] . "', '" . $arrBed['type'] . "', '" . $arrBed['configuration_id'] . "')
										 ";
						$objDB->query($stmt);
					}					
				}
			}
			$count += sizeof($arrRooms);			
		}
		while (sizeof($arrRooms) == $this->rows);
		// Возвращаем номера которые есть у данных отелей, чтобы не было ошибок при парсинге дальше
		$stmt = "SELECT ID_room FROM room WHERE ID_hotel IN (" . join(',', $this->arrHotelIds) . ")";
		return $objDB->selectSimpleArray($stmt);
	}

	
	/**
	 * Получаем услуги типы услуг номеров
	 *
	 * @return array - Массив данных
	 */
	public function getRoomFacilityTypes() {
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getRoomFacilityTypes'), array(
			'facilitytype_ids' => $this->arrFacilityTypeIds,
			'fields' => $this->arrFields, 
			'languagecodes' => $this->arrLanguageCodes, 
			'roomfacilitytype_ids' => $this->arrRoomFacilityTypeIds,
			'types' => $this->arrTypes		
		));
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Получаем и сохраняем типы услуг номеров
	 */
	public function parseRoomFacilityTypes() {
		$objDB = Service_Database::instance();
		foreach ($this->_arrSystemLang as $lang) {
			$this->arrLanguageCodes = array($lang);		
			$arrRoomFacilityTypes = $this->getRoomFacilityTypes();
			if (empty($arrRoomFacilityTypes) || isset($arrRoomFacilityTypes['fault'])) continue;
			foreach ($arrRoomFacilityTypes as $arrRoomFacilityType) {
				$arrRoomFacilityType['name'] = Service_Escape::absolutelyEscapeString($arrRoomFacilityType['name']);
				$stmt = "INSERT INTO room_facility_type (`ID_room_facility_type`,`ID_facility_type`,`room_facility_type_type`,`room_facility_type_name_" . $lang . "`) 
								 VALUES ('" . $arrRoomFacilityType['roomfacilitytype_id'] . "','" . $arrRoomFacilityType['facilitytype_id'] . "','" . $arrRoomFacilityType['type'] . "', '" . $arrRoomFacilityType['name'] . "')
								 ON DUPLICATE KEY UPDATE 
								 `room_facility_type_name_" . $lang . "` = VALUES(`room_facility_type_name_" . $lang . "`)";
				$objDB->query($stmt);
			}
		}
	}
	
	/**
	 * Получаем услуги номеров
	 *
	 * @return array - Массив данных
	 */
	public function getRoomFacilities() {
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getRoomFacilities'), array(
			'city_ids' => $this->arrCityIds,
			'classes' => $this->arrClasses, 
			'countrycodes' => $this->arrCountryCodes,
			'facilitytype_ids' => $this->arrFacilityTypeIds,
			'hotel_ids' => $this->arrHotelIds,  
			'hotelfacilitytype_ids' => $this->arrHotelFacilityTypeIds, 
			'fields' => $this->arrFields,  
			'rows' => $this->rows, 
			'offset' => $this->offset, 
			'show_test' => $this->showTest,
			'last_change' => $this->lastChange
		));
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Получаем и сохраняем услуги номеров
	 * 
	 * @param array $arrRoomIds - Массив с ID номеров, которые надо парсить
	 */
	public function parseRoomFacilities(array $arrRoomIds) {
		$objDB = Service_Database::instance();	
		if (!empty($this->arrHotelIds)) { // Удаляем услуги если знаем какие отели парсим
			$stmt = "DELETE FROM room_facility WHERE ID_hotel IN (" . join(',', $this->arrHotelIds) . ")";
			$objDB->query($stmt);				
		}
		$count = 0;
		do {
			$this->offset = $count;	
			$arrRoomFacilities = $this->getRoomFacilities();
			if (empty($arrRoomFacilities) || isset($arrRoomFacilities['fault'])) break;
			foreach ($arrRoomFacilities as $arrRoomFacility) {
				if (!in_array($arrRoomFacility['room_id'], $arrRoomIds)) continue;
				$stmt = "INSERT IGNORE INTO room_facility (`ID_room`,`ID_hotel`,`ID_room_facility_type`,`ID_facility_type`,`value`) 
								 VALUES ('" . $arrRoomFacility['room_id'] . "', '" . $arrRoomFacility['hotel_id'] . "', '" . $arrRoomFacility['roomfacilitytype_id'] . "', '" . $arrRoomFacility['facilitytype_id'] . "', '" . $arrRoomFacility['value'] . "')";
				$objDB->query($stmt);
				// Обновляем строковую запись услуг в номере
				$stmt = "UPDATE `room`
					SET `str_facilities` = (
						SELECT GROUP_CONCAT(`room_facility`.`ID_room_facility_type`) AS `str_facilities`
    				FROM `room_facility`
    				WHERE `room_facility`.`ID_room` = `room`.`ID_room`
						GROUP BY `ID_room`
					)
					WHERE `room`.`ID_room` = " . intval($arrRoomFacility['room_id']) . "
				";
				$objDB->query($stmt);
			}
			$count += sizeof($arrRoomFacilities);							
		}
		while (sizeof($arrRoomFacilities) == $this->rows);
	}	
	
/**
	 * Получаем описание номеров
	 *
	 * @return array - Массив данных
	 */
	public function getRoomDescriptions() {
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getRoomTranslations'), array(
			'hotel_ids' => $this->arrHotelIds, 
			'city_ids' => $this->arrCityIds, 
			'classes' => $this->arrClasses, 
			'countrycodes' => $this->arrCountryCodes,
			'languagecodes' => $this->arrLanguageCodes, 
			'fields' => $this->arrFields, 
			'room_ids' => $this->arrRoomIds, 
			'rows' => $this->rows, 
			'offset' => $this->offset, 
			'show_test' => $this->showTest,
			'last_change' => $this->lastChange)
		);
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Получаем и сохраняем описание номеров
	 *
	 * @param array $arrRoomIds - Массив с ID номеров, которые надо парсить
	 */
	public function parseRoomDescriptions(array $arrRoomIds) {
		$objDB = Service_Database::instance();		
		if (!empty($this->arrHotelIds)) { // Удаляем описания если знаем с какими отелями работаем
			$stmt = "DELETE FROM room_description WHERE ID_hotel IN (" . join(',', $this->arrHotelIds) . ")";
			$objDB->query($stmt);				
		}							
		foreach ($this->_arrSystemLang as $lang) {
			$this->arrLanguageCodes = array($lang);
			$count = 0;				
			do {			
				$this->offset = $count;	
				$arrRoomDescriptions = $this->getRoomDescriptions();
				if (empty($arrRoomDescriptions) || isset($arrRoomDescriptions['fault'])) break;
				foreach ($arrRoomDescriptions as $arrRoomDescription) {
					if (!in_array($arrRoomDescription['room_id'], $arrRoomIds)) continue;
					$arrRoomDescription['description'] = Service_Escape::absolutelyEscapeString($arrRoomDescription['description']);
					$arrRoomDescription['name'] = Service_Escape::absolutelyEscapeString($arrRoomDescription['name']);
					$stmt = "INSERT INTO room_description (`ID_room`,`ID_hotel`,`room_name_" . $lang . "`,`room_description_" . $lang . "`) 
									 VALUES ('" . $arrRoomDescription['room_id'] . "','" . $arrRoomDescription['hotel_id'] . "', '" . $arrRoomDescription['name'] . "', '" . $arrRoomDescription['description'] . "')
									 ON DUPLICATE KEY UPDATE 
									 `room_description_" . $lang . "` = VALUES(`room_description_" . $lang . "`),
									 `room_name_" . $lang . "` = VALUES(`room_name_" . $lang . "`)";
					$objDB->query($stmt);
				}
				$count += sizeof($arrRoomDescriptions);				
			}
			while (sizeof($arrRoomDescriptions) == $this->rows);
		}
	}			
	
	/**
	 * Получаем фотографии номеров
	 *
	 * @return array - Массив данных
	 */
	public function getRoomPhotos() {
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getRoomPhotos'), array(
			'hotel_ids' => $this->arrHotelIds, 
			'city_ids' => $this->arrCityIds,
			'room_ids' => $this->arrRoomIds,  
			'classes' => $this->arrClasses, 
			'countrycodes' => $this->arrCountryCodes, 
			'fields' => $this->arrFields,  
			'rows' => $this->rows, 
			'offset' => $this->offset, 
			'show_test' => $this->showTest,
			'last_change' => $this->lastChange)
		);
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Получаем и сохраняем фотографии номеров
	 *
	 * @param array $arrRoomIds - Массив с ID номеров, которые надо парсить
	 */
	public function parseRoomPhotos(array $arrRoomIds) {
		$objDB = Service_Database::instance();	
		if (!empty($this->arrHotelIds)) { // Удаляем фотки номеров если знаем какие отели парсим
			$stmt = "DELETE FROM room_photo WHERE ID_hotel IN (" . join(',', $this->arrHotelIds) . ")";
			$objDB->query($stmt);
		}				
		$count = 0;
		do {			
			$this->offset = $count;	
			$arrRoomPhotos = $this->getRoomPhotos();
			if (empty($arrRoomPhotos) || isset($arrRoomPhotos['fault'])) break;
			foreach ($arrRoomPhotos as $arrRoomPhoto) {
				if (!in_array($arrRoomPhoto['room_id'], $arrRoomIds)) continue;
				$stmt = "INSERT INTO room_photo (`ID_photo`,`ID_room`,`ID_hotel`,`url_original`,`url_max_300`,`url_square_60`) 
								 VALUES ('" . $arrRoomPhoto['photo_id'] . "', '" . $arrRoomPhoto['room_id'] . "', '" . $arrRoomPhoto['hotel_id'] . "', '" . $arrRoomPhoto['url_original'] . "', '" . $arrRoomPhoto['url_max300'] . "', '" . $arrRoomPhoto['url_square60'] . "')
								 ON DUPLICATE KEY UPDATE 
								 `ID_room` = VALUES(`ID_room`),
								 `ID_hotel` = VALUES(`ID_hotel`),
								 `url_original` = VALUES(`url_original`),
								 `url_max_300` = VALUES(`url_max_300`),
								 `url_square_60` = VALUES(`url_square_60`)";
				$objDB->query($stmt);
			}
			$count += sizeof($arrRoomPhotos);			
		}
		while (sizeof($arrRoomPhotos) == $this->rows);
	}	
	
	/**
	 * Получаем логотипы отелей
	 *
	 * @return array - Массив данных
	 */
	public function getHotelLogoPhotos() {
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getHotelLogoPhotos'), array(
			'hotel_ids' => $this->arrHotelIds, 
			'city_ids' => $this->arrCityIds,
			'room_ids' => $this->arrRoomIds,  
			'countrycodes' => $this->arrCountryCodes, 
			'fields' => $this->arrFields,  
			'rows' => $this->rows, 
			'offset' => $this->offset, 
			'show_test' => $this->showTest,		
			'last_change' => $this->lastChange)
		);
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Получаем и сохраняем логотипы отелей
	 */
	public function parseHotelLogoPhotos() {
		$objDB = Service_Database::instance();	
		if (!empty($this->arrHotelIds)) { // Удаляем логотипы, если знаем какие отели парсим
			$stmt = "DELETE FROM hotel_logo WHERE ID_hotel IN (" . join(',', $this->arrHotelIds) . ")";
			$objDB->query($stmt);				
		}				
		$count = 0;
		do {			
			$this->offset = $count;	
			$arrHotelLogoPhotos = $this->getHotelLogoPhotos();
			if (empty($arrHotelLogoPhotos) || isset($arrHotelLogoPhotos['fault'])) break;
			foreach ($arrHotelLogoPhotos as $arrHotelLogoPhoto) {
				$stmt = "INSERT INTO hotel_logo (`ID_photo`,`ID_hotel`,`url_original`,`url_max_300`,`url_square_60`) 
								 VALUES ('" . $arrHotelLogoPhoto['photo_id'] . "', '" . $arrHotelLogoPhoto['hotel_id'] . "', '" . $arrHotelLogoPhoto['url_original'] . "', '" . $arrHotelLogoPhoto['url_max300'] . "', '" . $arrHotelLogoPhoto['url_square60'] . "')
								 ON DUPLICATE KEY UPDATE 
								 `ID_hotel` = VALUES(`ID_hotel`),
								 `url_original` = VALUES(`url_original`),
								 `url_max_300` = VALUES(`url_max_300`),
								 `url_square_60` = VALUES(`url_square_60`)";
				$objDB->query($stmt);
			}
			$count += sizeof($arrHotelLogoPhotos);			
		}
		while (sizeof($arrHotelLogoPhotos) == $this->rows);
	}

	/**
	 * Получаем логотипы отелей
	 *
	 * @return array - Массив данных
	 */
	public function getHotelPhotos() {
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getHotelPhotos'), array(
			'hotel_ids' => $this->arrHotelIds, 
			'city_ids' => $this->arrCityIds,
			'classes' => $this->arrClasses,  
			'countrycodes' => $this->arrCountryCodes, 
			'fields' => $this->arrFields,  
			'rows' => $this->rows, 
			'offset' => $this->offset, 
			'show_test' => $this->showTest,
			'last_change' => $this->lastChange)
		);
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Получаем и сохраняем фотографии отелей
	 */
	public function parseHotelPhotos() {
		$objDB = Service_Database::instance();			
		$count = 0;
		if (!empty($this->arrHotelIds)) { // Удаляем фотографии если знаем какие отели парсим
			$stmt = "DELETE FROM hotel_photo WHERE ID_hotel IN (" . join(',', $this->arrHotelIds) . ")";
			$objDB->query($stmt);
		}
		do {
			$this->offset = $count;	
			$arrHotelPhotos = $this->getHotelPhotos();		
			if (empty($arrHotelPhotos) || isset($arrHotelPhotos['fault'])) break;
			foreach ($arrHotelPhotos as $arrHotelPhoto) {
				$stmt = "INSERT INTO hotel_photo (`ID_photo`,`ID_hotel`,`url_original`,`url_max_300`,`url_square_60`) 
								 VALUES ('" . $arrHotelPhoto['photo_id'] . "', '" . $arrHotelPhoto['hotel_id'] . "', '" . $arrHotelPhoto['url_original'] . "', '" . $arrHotelPhoto['url_max300'] . "', '" . $arrHotelPhoto['url_square60'] . "')
								 ON DUPLICATE KEY UPDATE 
								 `ID_hotel` = VALUES(`ID_hotel`),
								 `url_original` = VALUES(`url_original`),
								 `url_max_300` = VALUES(`url_max_300`),
								 `url_square_60` = VALUES(`url_square_60`)";
				$objDB->query($stmt);
			}
			$count += sizeof($arrHotelPhotos);				
		}
		while (sizeof($arrHotelPhotos) == $this->rows);
	}

	/**
	 * Получаем типы отелей
	 *
	 * @return array - Массив данных
	 */
	public function getHotelTypes() {
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getHotelTypes'), array(
			'hoteltype_ids' => $this->arrFacilityTypeIds,
			'fields' => $this->arrFields, 
			'languagecodes' => $this->arrLanguageCodes, 
		));
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Получаем и сохраняем типы отелей
	 */
	public function parseHotelTypes() {
		$objDB = Service_Database::instance();
		foreach ($this->_arrSystemLang as $lang) {
			$this->arrLanguageCodes = array($lang);		
			$arrHotelTypes = $this->getHotelTypes();
			if (empty($arrHotelTypes) || isset($arrHotelTypes['fault'])) continue;
			foreach ($arrHotelTypes as $arrHotelType) {
				$arrHotelType['name'] = Service_Escape::absolutelyEscapeString($arrHotelType['name']);
				$stmt = "INSERT INTO hotel_type (`ID_hotel_type`,`hotel_type_name_" . $lang . "`) 
								 VALUES ('" . $arrHotelType['hoteltype_id'] . "', '" . $arrHotelType['name'] . "')
								 ON DUPLICATE KEY UPDATE 
								 `hotel_type_name_" . $lang . "` = VALUES(`hotel_type_name_" . $lang . "`)";
				$objDB->query($stmt);
			}
		}
	}

/**
	 * Получаем перводы на языки для отеля
	 *
	 * @return array - Массив данных
	 */
	public function getHotelLang() {
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getHotelTranslations'), array(
			'hotel_ids' => $this->arrHotelIds, 
			'city_ids' => $this->arrCityIds, 
			'classes' => $this->arrClasses, 
			'countrycodes' => $this->arrCountryCodes,
			'languagecodes' => $this->arrLanguageCodes, 
			'fields' => $this->arrFields, 
			'rows' => $this->rows, 
			'offset' => $this->offset, 
			'show_test' => $this->showTest,
			'last_change' => $this->lastChange)
		);
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Получаем и сохраняем перводы на языки для отеля
	 */
	public function parseHotelLang($lang = 'ru') {
		$objDB = Service_Database::instance();			
		$count = 0;
		$this->arrLanguageCodes = array($lang);		
		do {			
			$this->offset = $count;	
			$arrHotels = $this->getHotelLang();	
			if (empty($arrHotels) || isset($arrHotels['fault'])) break;
			foreach ($arrHotels as $arrHotel) {
				$arrHotel['address'] = Service_Escape::absolutelyEscapeString($arrHotel['address']);
				$arrHotel['name'] = Service_Escape::absolutelyEscapeString($arrHotel['name']);
				$stmt = "UPDATE hotel
				 				 SET address_" . $lang . " = '" . $arrHotel['address'] . "',
				 				 hotel_name_" . $lang . " = '" . $arrHotel['name'] . "'
				 				 WHERE ID_hotel = '" . $arrHotel['hotel_id'] . "'";																										
				$objDB->query($stmt);
			}
			$count += sizeof($arrHotels);			
		}
		while (sizeof($arrHotels) == $this->rows);
	}			
	
	/**
	 * Получаем ID измененых отелей 
	 * 
	 * @return array - Массив данных
	 */
	public function getChangedHotels() {
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getChangedHotels'), array(
			'hotel_ids' => $this->arrHotelIds, 
			'city_ids' => $this->arrCityIds,
			'classes' => $this->arrClasses,  
			'countrycodes' => $this->arrCountryCodes, 
			'fields' => $this->arrFields,  
			'rows' => $this->rows, 
			'offset' => $this->offset, 
			'show_test' => $this->showTest,
			'last_change' => $this->lastChange
		));
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Получаем всех ID измененых отелей 
	 */
	public function getAllChangedHotels() {
		$count = 0;
		$arrReturn = array();
		do {			
			$this->offset = $count;	
			$arrHotels = $this->getChangedHotels();
			if (empty($arrHotels) || isset($arrHotels['fault'])) break;
			$arrReturn = Service_ArrayConverter::getColumn($arrHotels, 'hotel_id');
			$count += sizeof($arrHotels);			
		}
		while (sizeof($arrHotels) == $this->rows);
		return $arrReturn;
	}

	/**
	 * Получаем отели
	 *
	 * @return array - Массив данных
	 */
	public function getHotels() {
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getHotels'), array(
			'hotel_ids' => $this->arrHotelIds, 
			'city_ids' => $this->arrCityIds,
			'classes' => $this->arrClasses,  
			'countrycodes' => $this->arrCountryCodes, 
			'fields' => $this->arrFields,  
			'rows' => $this->rows, 
			'offset' => $this->offset, 
			'show_test' => $this->showTest,		
			'last_change' => $this->lastChange)
		);
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Получаем и сохраняем отели
	 */
	public function parseHotels() {
		$objDB = Service_Database::instance();			
		$count = 0;
		do {			
			$this->offset = $count;	
			$arrHotels = $this->getHotels();
			if (empty($arrHotels) || isset($arrHotels['fault'])) break;
			$arrCityIds = Service_ArrayConverter::getColumn($arrHotels, 'city_id');
			$stmt = "SELECT ID_city FROM city WHERE ID_city IN (" . join(',', $arrCityIds) . ")";
			$arrDBCityIds = $objDB->selectSimpleArray($stmt);
			if (sizeof($arrDBCityIds) != sizeof($arrCityIds)) { // Если в БД городов меньше
				foreach ($arrHotels as $key => $arrHotel) {
					// Если города нет в БД, то не добавляем этот отель
					if (!in_array($arrHotel['city_id'], $arrDBCityIds)) {
						unset($arrHotels[$key]);
						foreach ($this->arrCityIds as $i => $cityId ) { // Удаляем и из массива для последующих запросов
							if ($cityId == $arrHotel['city_id']) unset($this->arrCityIds[$i]); 
						}
					}
				}
			}
			$stmt = "SELECT country_code FROM country";
			$arrCountryCodes = $objDB->selectSimpleArray($stmt);
			foreach ($arrHotels as $arrHotel) {
				// Пропускаем страны которых нет
				if (!in_array($arrHotel['countrycode'], $arrCountryCodes)) continue;
			  
				$stmt = "SELECT `hotel`.`ID_hotel` 
				FROM `hotel`
				WHERE `hotel`.`ID_hotel` = '" . $arrHotel['hotel_id'] . "'";
				
				if (! $objDB->isRecordExist($stmt)) {
					$stmt = "INSERT INTO hotel (
`ID_hotel`,
`ID_hotel_type`,
`ID_city`,
`country_code`,
`address_en`,
`check_in_from`,
`check_in_to`,
`check_out_from`,
`check_out_to`,
`class_is_estimated`,
`class`,
`currency_code`,
`is_closed`,
`latitude`,
`longitude`,
`max_persons_in_reservation`,
`min_rate`,
`max_rate`,
`max_rooms_in_reservation`,
`hotel_name_en`,
`nr_rooms`,
`is_preferred`,
`ranking`,
`review_nr`,
`review_score`,
`url`,
`zip`,
`last_parse`) 
VALUES (
'" . $arrHotel['hotel_id'] . "',
'" . $arrHotel['hoteltype_id'] . "',
'" . $arrHotel['city_id'] . "',
'" . $arrHotel['countrycode'] . "',
'" . Service_Escape::absolutelyEscapeString($arrHotel['address']) . "',
'" . Service_Escape::absolutelyEscapeString($arrHotel['checkin']['from']) . "',
'" . Service_Escape::absolutelyEscapeString($arrHotel['checkin']['to']) . "',
'" . Service_Escape::absolutelyEscapeString($arrHotel['checkout']['from']) . "',
'" . Service_Escape::absolutelyEscapeString($arrHotel['checkout']['to']) . "',
'" . $arrHotel['class_is_estimated'] . "',
'" . $arrHotel['class'] . "',
'" . $arrHotel['currencycode'] . "',
'" . $arrHotel['is_closed'] . "',
'" . $arrHotel['location']['latitude'] . "',
'" . $arrHotel['location']['longitude'] . "',
'" . $arrHotel['max_persons_in_reservation'] . "',
'" . $arrHotel['minrate'] . "',
'" . $arrHotel['maxrate'] . "',
'" . $arrHotel['max_rooms_in_reservation'] . "',
'" . Service_Escape::absolutelyEscapeString($arrHotel['name']) . "',
'" . $arrHotel['nr_rooms'] . "',
'" . $arrHotel['preferred'] . "',
'" . $arrHotel['ranking'] . "',
'" . $arrHotel['review_nr'] . "',
'" . $arrHotel['review_score'] . "',
'" . $arrHotel['url'] . "',
'" . Service_Escape::absolutelyEscapeString($arrHotel['zip']) . "',
'" . Service_Date::gLocalTime2BD() . "'
)";
				}
				else {
					$stmt = "UPDATE `hotel` SET
`ID_hotel_type` = '" . $arrHotel['hoteltype_id'] . "',
`ID_city` = '" . $arrHotel['city_id'] . "',
`country_code` = '" . $arrHotel['countrycode'] . "',
`address_en` = '" . Service_Escape::absolutelyEscapeString($arrHotel['address']) . "',
`check_in_from` = '" . Service_Escape::absolutelyEscapeString($arrHotel['checkin']['from']) . "',
`check_in_to` = '" . Service_Escape::absolutelyEscapeString($arrHotel['checkin']['to']) . "',
`check_out_from` = '" . Service_Escape::absolutelyEscapeString($arrHotel['checkout']['from']) . "',
`check_out_to` = '" . Service_Escape::absolutelyEscapeString($arrHotel['checkout']['to']) . "',
`class_is_estimated` = '" . $arrHotel['class_is_estimated'] . "',
`class` = '" . $arrHotel['class'] . "',
`currency_code` = '" . $arrHotel['currencycode'] . "',
`is_closed` = '" . $arrHotel['is_closed'] . "',
`latitude` = '" . $arrHotel['location']['latitude'] . "',
`longitude` = '" . $arrHotel['location']['longitude'] . "',
`max_persons_in_reservation` = '" . $arrHotel['max_persons_in_reservation'] . "',
`min_rate` = '" . $arrHotel['minrate'] . "',
`max_rate` = '" . $arrHotel['maxrate'] . "',
`max_rooms_in_reservation` ='" . $arrHotel['max_rooms_in_reservation'] . "',
`hotel_name_en` = '" . Service_Escape::absolutelyEscapeString($arrHotel['name']) . "',
`nr_rooms` = '" . $arrHotel['nr_rooms'] . "',
`is_preferred` = '" . $arrHotel['preferred'] . "',
`ranking` = '" . $arrHotel['ranking'] . "',
`review_nr` = '" . $arrHotel['review_nr'] . "',
`review_score` = '" . $arrHotel['review_score'] . "',
`url` = '" . $arrHotel['url'] . "',
`zip` = '" . Service_Escape::absolutelyEscapeString($arrHotel['zip']) . "',
`last_parse` = '" . Service_Date::gLocalTime2BD() . "'
WHERE `hotel`.`ID_hotel` = '" . $arrHotel['hotel_id'] . "'
LIMIT 1";
				}
				$objDB->query($stmt);
				$objHotel = new Hotel($arrHotel['hotel_id']);
				$objHotel->updateHotelFinalName();
			}
			$count += sizeof($arrHotels);
			
		}
		while (sizeof($arrHotels) == $this->rows);
	}
	
	/**
	/**
	 * Получаем доступность отелей
	 * 
	 * @param string $arrivalDate - Дата заезда
	 * @param string $departureDate - Дата выезда
	 * @param int $maxPersons - Кол-во человек
	 * @param int $availableRooms - Минимальное кол-во номеров в отеле 
	 * @param float $latitude - Широта
	 * @param float $longitude - Долгота
	 * @param int $radius - Радиус поиска отелей
	 * @param array $arrGuests - Массив гостей по номерам (array(2, 2, 1))
	 * @param array $arrChildren - Массив детей по номерам (array(0, 0, 2))
	 * 
	 * @return array - Массив данных 
	 */
	public function getHotelAvailability($arrivalDate, $departureDate, $maxPersons = null, $availableRooms = 1, $latitude = '', $longitude = '', $radius = '', array $arrGuests = array(), array $arrChildren = array()) {
		Service_Debug::setDebug();
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getHotelAvailability'), array(
			'hotel_ids' => $this->arrHotelIds, 
			'city_ids' => $this->arrCityIds,
			'arrival_date' => $arrivalDate,  
			'departure_date' => $departureDate, 
			'classes' => $this->arrClasses, 
			'latitude' => $latitude, 
			'longitude' => $longitude, 
			'max_persons' => -$maxPersons, 
			'show_test' => $this->showTest,
			'available_rooms' => $availableRooms,
			'guest_qty' => $arrGuests,
			'children_qty' => $arrChildren,
			'children_qty' => $arrChildren,
			'radius' => $radius,
			'show_flash_deals' => 1,
			'affiliate_id' => 319657,
		));
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Получаем доступность блоков отелей
	 * 
	 * @param string $arrivalDate - Дата заезда
	 * @param string $departureDate - Дата выезда
	 * @param int $detailLevel - Флаг для большей детализации (фотки, правила, описания)
	 * @param int $info - Флаг для получения доп.инфы в правилах
	 * 
	 * @return array - Массив данных 
	 */
	public function getBlockAvailability($arrivalDate, $departureDate, $detailLevel = 0, $info = 0) {
		Service_Debug::setDebug();
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getBlockAvailability'), array(
			'hotel_ids' => $this->arrHotelIds, 
			'arrival_date' => $arrivalDate,  
			'departure_date' => $departureDate, 
			'important_information' => $info,
			'show_test' => $this->showTest,		
			'detail_level' => $detailLevel,
			'languagecode' => $this->arrLanguageCodes,
			'show_flash_deals' => 1,
			'affiliate_id' => 319657,
		));
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Бронируем отель
	 * 
	 * @param Booking $objBooking - Объект с данными по бронированию
	 * @param string $dateArr - Дата заезда
	 * @param string $dateDep - Дата отъезда
	 * @param int $hotelId - ID отеля
	 */
	public function processBooking(Booking $objBooking, $dateArr, $dateDep, $hotelId) {
		Service_Debug::setDebug();
		list($expMonth, $expYear) = explode('/', $objBooking->getField('cc_expiration_date'));
		$arrBlockIds = Service_ArrayConverter::getColumn($objBooking->tableFields['Room'], 'ID_block');
		$arrBlockQty = Service_ArrayConverter::getRepeats($arrBlockIds);
		
		// Создаем массив с ценами под формат Booking.com
		$arrFullIncrementalPrice = array();
		$blockId = 0;
		$i = 0;		
		$arrGuestNames = array();
		foreach ($objBooking->tableFields['Room'] as $arrRoom) {
			if ($arrRoom['ID_block'] != $blockId) {
				$i++;
				$arrFullIncrementalPrice[$i] = 0;
				$blockId = $arrRoom['ID_block'];			
			}
			$arrFullIncrementalPrice[$i] += $arrRoom['price'];
			$arrGuestNames[] = substr($arrRoom['guest_name'], 0, strpos($arrRoom['guest_name'], ','));
		}
		
		$objCurl = new Service_Curl();
		$objCurl->useSSL = true;
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('processBooking', true), array(
			'affiliate_id' => 319657,
			'affiliate_label' => '',
			'guest_city' => $objBooking->getField('city'), 
			'guest_email' => (defined('MAIL_CLASS_DEFINED') ? 'slamer86@gmail.com' : $objBooking->getField('our_e_mail')),
			'guest_country' => $objBooking->getField('country_code'),
			'begin_date' => Service_Date::dateToBD($dateArr),
			'block_id' => array_unique($arrBlockIds),
			'block_qty' => $arrBlockQty,
			'cc_cardholder' => $objBooking->getField('cc_cardholder'), 
			'cc_cvc' => $objBooking->getField('cc_cvc'),
			'cc_expiration_date' => '20' . $expYear . '-' . $expMonth . '-01',
			'cc_number' => $objBooking->getField('cc_number'),
			'cc_type' => $objBooking->getField('ID_credit_card'),
			'comments' => $objBooking->getField('comment'),
			'dc_issue_number' => null, 
			'dc_start_date' => null,
			'end_date' => Service_Date::dateToBD($dateDep),
			'guest_language' => null,
			'booker_firstname' => $objBooking->getField('booker_first_name'),
			'booker_lastname' => $objBooking->getField('booker_last_name'),
			'guest_name' => $arrGuestNames,
			'guest_qty' => Service_ArrayConverter::getColumn($objBooking->tableFields['Room'], 'guest_qty'),
			'guest_street' => $objBooking->getField('address'),
			'guest_telephone' => $objBooking->getField('home_phone'),
			'guest_zip' => $objBooking->getField('zip'),
			'hotel_id' => $hotelId,
			'incremental_prices' => $arrFullIncrementalPrice,
			'show_test' => $this->showTest,
			'test_mode' => $this->test, 
			'smoking' => Service_ArrayConverter::getColumn($objBooking->tableFields['Room'], 'smoking'),			
		));
		$arrResult =  $this->_processResult($arrResult);
		if (isset($arrResult['fault'])) { // Сохраняем ошибки
			$objError = new Error();
		  $objError->setFields(array('error_name' => 'processBooking', 'error_text' => Service_Escape::absolutelyEscapeString($arrResult['fault']['string'])));
		  $objError->save();
		}
		return $arrResult;
	}	

	/**
	 * Отменяем бронирование
	 * 
	 * @param int $bookingId - ID бронирования
	 * @param string $pincode - Пин-код для отмены (4 цифры) 
	 * @param string $reason - Причина отмены
	 * 
	 * @return array - Массив данных
	 */
	public function cancelBooking($bookingId, $pincode, $reason = 'Reason') {
		Service_Debug::setDebug();
		$objCurl = new Service_Curl();
		$objCurl->useSSL = true;
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('cancelBooking', 1), array(
			'id' => $bookingId,
			'pincode' => $pincode, 
			'reason' => $reason,			
		));
		return $this->_processResult($arrResult);
	}		
	
	/**
	 * Получаем информацию о предоплате из всех условий номераа
	 * 
	 * @param string $policyText - Текст с информацией об условиях номера
	 * 
	 * @return string - Текст с информацией о предоплате
	 */
	public static function getRoomPolicyPrePay($policyText) {
		Service_Debug::setDebug();
		$arrText = array();
		$policyText = str_replace(array("\n", '</div>', ' .'), array(' ', "</div>\n", '.') ,$policyText);
		preg_match('#div class="POLICY_PREPAY"\>(.+)#', $policyText, $arrText);
	  return empty($arrText[1]) ? '' : $arrText[1];
	}
	
	/**
	 * Получаем информацию о детских и дополнительных кроватях из всех условий отеля
	 * 
	 * @param string $policyText - Текст с информацией об условиях отеля
	 * 
	 * @return $policyText - Текст с информацией о кроватях
	 */
	public function getChildrenPolicy($policyText) {
		Service_Debug::setDebug();
		$arrText = array();
		$policyText = str_replace(array("\n", '</div>', ' .', '.'), array(' ', "</div>\n", '.', '.<br />') ,$policyText);
		preg_match('#div class="POLICY_CHILDREN"\>(.+)#', $policyText, $arrText);
	  if (!empty($arrText[1])) $policyText = $arrText[1];
	  return empty($policyText) ? '' : $policyText;
	}
	
	/**
	 * Парсим информацию о детских и дополнительных кроватях
	 * 
	 * @param string $policyText - Текст с информацией об условиях отеля
	 * 
	 * @return $arrChildren - Массив с информацией о кроватях
	 */
	public function parseChildrenPolicy($policyText) {
		Service_Debug::setDebug();
		$arrChildren = array();
		$policyText = $this->getChildrenPolicy($policyText);
		
// Общие данные по детям
	  if (preg_match('|Children cannot be accommodated at the hotel|', $policyText)) $arrChildren['welcome'] = 0;
		elseif (preg_match('|All children are welcome|', $policyText)) $arrChildren['welcome'] = 1;
		elseif (preg_match('|Children older than ([0-9]+) years are welcome|', $policyText, $arrYears)) {
			$arrChildren['welcome'] = 2;
			$arrChildren['years'] = $arrYears[1];
		}
		else $arrChildren['welcome'] = 3;
// Существующие кровати
		$arrChildren['existing'] = array();
		// Существующие кровати бесплатно
		preg_match('#(All|One|Up to two)( further)? child(ren)? under ([0-9]+) years stay(s)? free of charge when using existing beds#', $policyText, $arrExistingBeds);
		if (isset($arrExistingBeds[0])) {
			$i = sizeof($arrChildren['existing']);
			$arrChildren['existing'][$i]['from'] = 0;
			$arrChildren['existing'][$i]['to'] = $arrExistingBeds[4];
			$arrChildren['existing'][$i]['price'] = 0;
			$arrChildren['existing'][$i]['num'] = ($arrExistingBeds[1] == 'One') ? 1 : (($arrExistingBeds[1] == 'Up to two') ? 2 : 10);
		}
		preg_match('#(All|One|Up to two)( further)? child(ren)? from ([0-9]+) to ([0-9]+) years stay(s)? free of charge when using existing beds#', $policyText, $arrExistingBeds);
		if (isset($arrExistingBeds[0])) {
			$i = sizeof($arrChildren['existing']);
			$arrChildren['existing'][$i]['from'] = $arrExistingBeds[4];
			$arrChildren['existing'][$i]['to'] = $arrExistingBeds[5];
			$arrChildren['existing'][$i]['price'] = 0;
			$arrChildren['existing'][$i]['num'] = ($arrExistingBeds[1] == 'One') ? 1 : (($arrExistingBeds[1] == 'Up to two') ? 2 : 10);
		}
		// Существующие кровати за деньги
		preg_match('#(All|One|Up to two)( further)? child(ren)? from ([0-9]+) to ([0-9]+) years (are|is) charged ([A-Z]{3}) ([0-9\.]+) [\w ]+ existing bed#', $policyText, $arrExistingBeds);
		if (!isset($arrExistingBeds[0])) preg_match('#(All|One|Up to two)( further)? child(ren)? from ([0-9]+) to ([0-9]+) years (are|is) charged ([0-9]+) (%)+ [\w ]+ existing bed#', $policyText, $arrExistingBeds);
		if (isset($arrExistingBeds[0])) {
			$i = sizeof($arrChildren['existing']);
			$arrChildren['existing'][$i]['from'] = $arrExistingBeds[4];
			$arrChildren['existing'][$i]['to'] = $arrExistingBeds[5];
			$arrChildren['existing'][$i]['num'] = ($arrExistingBeds[1] == 'One') ? 1 : (($arrExistingBeds[1] == 'Up to two') ? 2 : 10);
			if ($arrExistingBeds[8] == '%')	$arrChildren['existing'][$i]['percent'] = $arrExistingBeds[7];
		}				
		preg_match('#(All|One|Up to two)( further)? older child(ren)? or adult(s)? (are|is) charged ([A-Z]{3}) ([0-9\.]+) [\w ]+ existing bed#', $policyText, $arrExistingBeds);
		if (!isset($arrExistingBeds[0])) preg_match('#(All|One|Up to two)( further)? older child(ren)? or adult(s)? (are|is) charged ([0-9]+) (%) [\w ]+ existing bed#', $policyText, $arrExistingBeds);
		if (isset($arrExistingBeds[0])) {
			$i = sizeof($arrChildren['existing']);
			$max = 0;
			foreach ($arrChildren['existing'] as $extraBed) {
				$max = max($max, $extraBed['to']);
			}			
			$arrChildren['existing'][$i]['from'] = $max + 1;
			$arrChildren['existing'][$i]['to'] = 999;
			
			if ($arrExistingBeds[7] == '%')	$arrChildren['existing'][$i]['percent'] = $arrExistingBeds[6];
			else {
				$arrChildren['existing'][$i]['price'] = $arrExistingBeds[7];
				$arrChildren['existing'][$i]['curency'] = $arrExistingBeds[6];
			}
		}
// Детские кровати
		$arrChildren['cots'] = array();
		preg_match('#(All|One|Up to two)( further)? child(ren)? under ([0-9]+) years stay(s)? free of charge [\w ]+ cot#', $policyText, $arrCots);
		if (!isset($arrCots[0])) preg_match('#(All|One|Up to two)( further)? child(ren)? under ([0-9]+) years (is|are) charged ([A-Z]{3}) ([0-9\.]+) [\w ]+ cot#', $policyText, $arrCots);
		if (isset($arrCots[0])) {
			$arrChildren['cots']['from'] = 0;
			$arrChildren['cots']['to'] = $arrCots[4];
			$arrChildren['cots']['num'] = ($arrCots[1] == 'One') ? 1 : (($arrCots[1] == 'Up to two') ? 2 : 10);
			$arrChildren['cots']['allow'] = 1;
			if (isset($arrCots[7])) {
				$arrChildren['cots']['currency'] = $arrCots[6];
				$arrChildren['cots']['price'] = $arrCots[7];				
			}
			else $arrChildren['cots']['price'] = 0;
		}
// Дополнительные кровати
		$arrChildren['extra'] = array();
		// Дополнительные кровати бесплатно
		preg_match('#(All|One|Up to two)( further)? child(ren)? under ([0-9]+) years stays free of charge in an extra bed#', $policyText, $arrExtraBeds);
		if (isset($arrExtraBeds[0])) {
			$i = sizeof($arrChildren['extra']);
			$arrChildren['extra'][$i]['from'] = 0;
			$arrChildren['extra'][$i]['to'] = $arrExtraBeds[4];
			$arrChildren['extra'][$i]['num'] = ($arrExtraBeds[1] == 'One') ? 1 : (($arrExtraBeds[1] == 'Up to two') ? 2 : 10);
			$arrChildren['extra'][$i]['price'] = 0;
		}
		// Дополнительные кровати за деньги для детей
		preg_match('#(All|One|Up to two)( further)? child(ren)? from ([0-9]+) to ([0-9]+) years (are|is) charged ([A-Z]{3}) ([0-9\.]+) [\w ]+ extra bed#', $policyText, $arrExtraBeds);
		if (!isset($arrExtraBeds[0])) preg_match('#(All|One|Up to two)( further)? child(ren)? from ([0-9]+) to ([0-9]+) years (are|is) charged ([0-9]+) (%)+ [\w ]+ extra bed#', $policyText, $arrExtraBeds);
		if (isset($arrExtraBeds[0])) {
			$i = sizeof($arrChildren['extra']);
			$arrChildren['extra'][$i]['from'] = $arrExtraBeds[4];
			$arrChildren['extra'][$i]['to'] = $arrExtraBeds[5];
			$arrChildren['extra'][$i]['num'] = ($arrExtraBeds[1] == 'One') ? 1 : (($arrExtraBeds[1] == 'Up to two') ? 2 : 10);
			if ($arrExtraBeds[8] == '%') $arrChildren['extra'][$i]['percent'] = $arrExtraBeds[7];
			else {
				$arrChildren['extra'][$i]['currency'] = $arrExtraBeds[7];
				$arrChildren['extra'][$i]['price'] = $arrExtraBeds[8];
			}
		}
		// Дополнительные кровати за деньги для детей и взрослых
		preg_match('#(All|One|Up to two)( further)?( older)? child(ren)? or adult(s)? (are|is) charged ([A-Z]{3}) ([0-9\.]+) [\w ]+ extra bed#', $policyText, $arrExtraBeds);
		if (!isset($arrExtraBeds[0])) preg_match('#(All|One|Up to two)( further)?( older)? child(ren)? or adult(s)? (are|is) charged ([0-9]+) (%)+ [\w ]+ extra bed#', $policyText, $arrExtraBeds);
		if (isset($arrExtraBeds[0])) {
			$i = sizeof($arrChildren['extra']);
			$max = 0;
			foreach ($arrChildren['existing'] as $extraBed) {
				if ($extraBed['to'] != 999) $max = max($max, $extraBed['to']);
			}
			if (isset($arrChildren['cots']['to']) && $arrChildren['cots']['to'] != 999) $max = max($max, $arrChildren['cots']['to']);	
			foreach ($arrChildren['extra'] as $extraBed) {
				if ($extraBed['to'] != 999) $max = max($max, $extraBed['to']);
			}
			if (isset($arrChildren['years'])) $max = $arrChildren['years'] - 1;
			$arrChildren['extra'][$i]['from'] = $max + 1;
			$arrChildren['extra'][$i]['to'] = 999;			
			$arrChildren['extra'][$i]['num'] = ($arrExtraBeds[1] == 'One') ? 1 : (($arrExtraBeds[1] == 'Up to two') ? 2 : 10);
			if ($arrExtraBeds[8] == '%') {
				$arrChildren['extra'][$i]['percent'] = $arrExtraBeds[7];
			}
			else {
				$arrChildren['extra'][$i]['currency'] = $arrExtraBeds[7];
				$arrChildren['extra'][$i]['price'] = $arrExtraBeds[8];
			}		
		}
// Вместимость
		preg_match_all('#Maximum capacity of ([\w \/]+) in a room is ([0-9]+)#', $policyText, $arrCapacity);
		if (isset($arrCapacity[0][0])) {
			foreach ($arrCapacity[1] as $bedKey => $bedName) {
				$arrChildren['capacity'][$bedName] = $arrCapacity[2][$bedKey];
				switch ($bedName) {
					case 'extra beds/babycots':
						foreach ($arrChildren['extra'] as $key => $value) {
							$arrChildren['extra'][$key]['num'] = $arrCapacity[2][$bedKey];
						}
						$arrChildren['cots']['num'] = $arrCapacity[2][$bedKey];					
						break;
					case 'babycots':
						$arrChildren['cots']['num'] = $arrCapacity[2][$bedKey];
						break;
					case 'extra beds':
						foreach ($arrChildren['extra'] as $key => $value) {
							$arrChildren['extra'][$key]['num'] = $arrCapacity[2][$bedKey];
						}
						break;
				}
			}			
		}
		else $arrChildren['capacity'] = 0;

		return $arrChildren;
	}

	/**
	 * Получаем и добавляем в очередь на парсинг измененные отели
	 * 
	 * @param string $countryCode - Код страны
	 */	
	public function parseChangedHotels($countryCode = null) {
		Service_Debug::setDebug();
		$objDB = Service_Database::instance();
		if (empty($this->lastChange)) $this->lastChange = date('Y-m-d', time() - 24 * 3600);
		echo $this->lastChange;
		if (empty($countryCode)) {
			$stmt = "SELECT country_code FROM country";
			$arrCountryCodes = $objDB->selectSimpleArray($stmt);
		}
		else $arrCountryCodes = array($countryCode);
				
		foreach ($arrCountryCodes as $countryCode) {
			$this->arrCountryCodes = array($countryCode);
			$arrHotelIds = $this->getAllChangedHotels();
			if (empty($arrHotelIds) || isset($arrHotelIds['fault'])) continue;
			foreach ($arrHotelIds as $hotelId) {
				$stmt = "INSERT IGNORE INTO changed_hotel (
									ID_hotel, 
									country_code, 
									is_new, 
									created_at
								 ) 
							   VALUES (
							   	'" . $hotelId . "', 
							   	'" . $countryCode . "', 
							   	IF((SELECT ID_hotel FROM hotel WHERE ID_hotel = '" . $hotelId . "') IS NULL, 1, 0),
							   	'" . Service_Date::gLocalTime2BD() . "'
							   )";
				$objDB->query($stmt);				
			}			
		}
		// Все новые отели добавляем в таблицу hotel
		$stmt = "SELECT ID_hotel FROM changed_hotel WHERE is_new = 1";
		$arrHotelIds = $objDB->selectSimpleArray($stmt);
		foreach ($arrHotelIds as $hotelId) {
			$stmt = "INSERT IGNORE INTO hotel (ID_hotel) VALUES ('" . $hotelId . "')";
			$objDB->query($stmt);
		}				
	}
	
	/**
	 * Парсим измененные отели
	 * 
	 * @param $timeLimit - Лимит выполнения по времени
	 * @param $hotelId - ID отеля если хотим отпарсить только один отель
	 */	
	public function updateChangedHotels($timeLimit = 35, $hotelId = null) {
		Pressure::setStart();
		$objDB = Service_Database::instance();
		$stmtWhere = " 1";
		$stmt = "SELECT ID_hotel FROM changed_hotel
						 WHERE " . $stmtWhere . "
						 ORDER BY is_new DESC, IF(country_code = 'ru', 1, 0) DESC, created_at, ID_hotel 
			       LIMIT 1000";
		if ($hotelId) $arrHotelIds = array($hotelId);
		else $arrHotelIds = $objDB->selectSimpleArray($stmt);
		$size = sizeof($arrHotelIds);
		$pages = ceil($size/50);
		
		for ($i = 0; $i < $pages; $i++) {
			echo $i . "\n";
			// Берем по 50 отелей и парсим их
			$arrSliceHotelIds = Service_ArrayConverter::getArraySlice($arrHotelIds, $i * 50, 50);
			$this->arrHotelIds = $arrSliceHotelIds;
			$this->parseHotels();
			// Удаляем отели из очереди
			$stmt = "DELETE FROM changed_hotel WHERE ID_hotel IN (" . join(',', $arrSliceHotelIds) . ")";
			$objDB->query($stmt);
			// Удаляем отели по которым ничего нет			
			$stmt = "DELETE FROM hotel WHERE ID_hotel IN (" . join(',', $arrSliceHotelIds) . ") AND country_code IS NULL";
			$objDB->query($stmt);
			// Парсим все для отелей
			$stmt = "SELECT ID_hotel FROM hotel WHERE ID_hotel IN (" . join(',', $this->arrHotelIds) . ")";
			$this->arrHotelIds = $objDB->selectSimpleArray($stmt);
			if (!sizeof($this->arrHotelIds)) {
				$time = Pressure::calculateCurrentDuration();
				echo $i . ' - ' . $time . "\n";
				continue;
			}
			$this->parseChains();
			$this->parseCreditCards();
			$this->parseHotelDescriptions();
			$this->parseHotelDescriptionPhotos();
			$this->parseHotelFacilities();
			$this->parseHotelLang('ru');
			$this->parseHotelPhotos();
			$this->parseHotelLogoPhotos();
			$this->parseCreditCards();
			// Парсим все для номеров
			$arrRoomIds = $this->parseRooms();
			if ($arrRoomIds) {
				$this->parseRoomDescriptions($arrRoomIds); 
				$this->parseRoomFacilities($arrRoomIds);
				$this->parseRoomPhotos($arrRoomIds);
			}
			$this->arrHotelIds = array();
			$time = Pressure::calculateCurrentDuration();
			echo $i . ' - ' . $time . "\n";
			if ($time > $timeLimit) return true;						
		}			
	}

	/**
	 * Разбираем ошибки пришедшие от Booking.com
	 * 
	 * @param string $error - Ошибки от Booking.com
	 * 
	 * @return array - Массив ошибок в формате: Имя поля => Текст ошибки
	 */
	public function parseErrors($error) {
		Service_Debug::setDebug();
		$i = 0;
		$arrReturn = array();		
		if (preg_match('#guest_email#', $error)) {
			$arrReturn[++$i]['name'] = 'e_mail';
			$arrReturn[$i]['text'] = 'E-Mail';
		}
		if (preg_match('#guest_telephone#', $error)) {
			$arrReturn[++$i]['name'] = 'home_phone';
			$arrReturn[$i]['text'] = 'Телефон';
		}
		if (preg_match('#cc_type#', $error)) {
			$arrReturn[++$i]['name'] = 'ID_credit_card';
			$arrReturn[$i]['text'] = Service_Translate::getText('Тип кредитной карты');
		}		
		if (preg_match('#cc_number#', $error)) {
			$arrReturn[++$i]['name'] = 'cc_number';
			$arrReturn[$i]['text'] = Service_Translate::getText('Номер карты');
		}		
		if (preg_match('#cc_cvc#', $error)) {
			$arrReturn[++$i]['name'] = 'cc_cvc';
			$arrReturn[$i]['text'] = Service_Translate::getText('Код безопасности');
		}
		if (preg_match('#cc_expiration_date#', $error)) {
			$arrReturn[++$i]['name'] = 'cc_expiration_date';
			$arrReturn[$i]['text'] = Service_Translate::getText('Дата истечения срока действия');
		}
		return $arrReturn;
	}

	/**
	 * Получаем информацию от букинга по отелю на конкретные даты
	 * 
	 * @param array $arrBookParams - Параметры бронирования
	 * @param bool $bookingInfo - флаг возвращать ли инфу по блокам в неизменненным виде
	 * @param string $language - язык информации (по умолчанию берется из интерфейса пользователя)
	 */
	public function getHotelBookingInfo(array $arrBookParams, $bookingInfo = false, $language = null) {
		Service_Debug::setDebug();
		if (empty($language)) $language = Service_Translate::getLang();
		$arrReturn = array();
		
	  // Получаем инфу и блоки по отелю
		$this->arrHotelIds = array($arrBookParams['ID_hotel']);
	  $this->arrLanguageCodes = array($language);
	  if (User_User::getId() == 1 && $arrBookParams['ID_hotel'] == 11223) $this->showTest = 1;
	  $arrResult = $this->getBlockAvailability(Service_Date::dateToBD($arrBookParams['date_arr']), Service_Date::dateToBD($arrBookParams['date_dep']), 1, 1);
	  if (empty($arrResult) || isset($arrResult['fault'])) return array('cancellation' => '', 'policies' => '', 'deposit_required' => '', 'block' => array());
  
	  // Делаем многомерный массив если результат только один 
  	if (isset($arrResult[0]['block'][0])) $arrBlocks = $arrResult[0]['block'];
  	elseif (isset($arrResult[0]['block'])) $arrBlocks[0] = $arrResult[0]['block'];

  	$arrBlocks = Service_ArrayConverter::sortArray($arrBlocks, 'min_price');
  	
  	$objViewHotel = new View_Hotel();
  	
		// Формируем правила отеля
	  $arrReturn['policies'] = $objViewHotel->makeHotelText($arrResult[0]['hotel_text']); 	  	
	  preg_match_all('|div class="POLICY_CANCELLATION"\>(.+)|', $arrResult[0]['hotel_text'], $arrText);
	  if (!empty($arrText[1][0])) $cancellation = $arrText[1][0];
	  $arrReturn['cancellation'] = empty($cancellation) ? '' : Service_Escape::absolutelyEscapeString(str_replace('</div>', '', $cancellation));
	  $objHotel = new Hotel($arrBookParams['ID_hotel']);
	  $objHotel->cancellationPolicy = $arrReturn['cancellation']; 
  	$arrReturn['block'] = $bookingInfo ? View_Block::getBookingBlocks($arrBlocks, $objHotel) : View_Block::getBookBlocks($arrBlocks, $objHotel); 
  	return $arrReturn;
	}
	
	/**
	 * Возвращает текст отмены бронирования для номера 
	 * 
	 * @param array $arrBlock - Данные по номеру
	 * @param BaseHotel $objHotel - Отель
	 */
	public static function getRoomCancellationPolicy(array $arrBlock, BaseHotel $objHotel) {
		Service_Debug::setDebug();
		preg_match_all('#div class="POLICY_CANCELLATION">(.+?)</#', $arrBlock['block_text'], $arrText);
 		if (!empty($arrText[1][0])) {
 			$cancellation = Service_Escape::absolutelyEscapeString(str_replace('</div>', '', $arrText[1][0]));
 		}
 		if (!empty($arrBlock['refundable_until']) && $arrBlock['refundable']) {
 			$date = strtotime(preg_replace('# [-|+][0-9]{4}#', '', $arrBlock['refundable_until']));
 			$date = Service_Date::getRusDate(date('d/m/Y', $date), true) . ' ' . date('H:i:s', $date);  
 			$cancellation = Service_Translate::getText('Бесплатная отмена бронирования') . ' ' . Service_Translate::getText('до') . ' ' . $date . ' (' . Service_Translate::getText('по времени отеля') . '). ';
 			if (!empty($arrBlock['charge_after'])) {
 				$objExchange = Service_Exchange::instance();
 				$cancellation .= Service_Translate::getText('В случае отмены или изменения бронирования позднее этого срока или в случае незаезда взимается', $objExchange->getSpanPrice($arrBlock['charge_after'], $objHotel->getField('currency_code')));
 			}
 			else $cancellation .= Service_Translate::getText('Позднее этого времени действуют стандартные штрафы гостиницы') . '.';
		}
 		if (empty($cancellation)) $cancellation = $objHotel->cancellationPolicy;
 		return $cancellation;
	}

	/**
	 * Парсим или проверяем отели которые можно бронировать без кредитной карты
	 * 
	 * @param string $essenceType - Тип сущности по которой ищем отели (возможно и конкретный отель)
	 * @param int $essenceId - ID сущности по которой ищем отели
	 * @param bool $onlyCheck - Если только проверка, то в БД пишется только в случае изменения
	 * @param bool $checkNoCCHotels - Если необходимо только проверить отели с no_cc = 1
	 * 
	 * @return bool - Флаг можно ли бронировать без кредитной карты
	 */
	public function parseNoCreditCardHotels($essenceType, $essenceId, $onlyCheck = false, $checkNoCCHotels = false) {
		Service_Debug::setDebug();
		$timeLimit = 45;
		$objDB = Service_Database::instance();
		if ($checkNoCCHotels) $whereCond = "no_cc = 1 AND TIMESTAMPDIFF(MINUTE, no_cc_check, '" . Service_Date::gLocalTime2BD() . "') > 180"; 
		elseif(Service_Essence::isEssenceTypeCorrect($essenceType)) $whereCond = "ID_" . $essenceType . " = '" . $essenceId . "'";
		else throw new Exception('Wrong essence');
		$stmt = "SELECT hotel.ID_hotel, hotel.url, hotel.no_cc, hotel.no_cc_check
						 FROM hotel 
						 WHERE " . $whereCond . "
						 ORDER BY no_cc_check
						 LIMIT 100";		
		$arrHotels = $objDB->select($stmt);
		$objCurl = new Service_Curl();
		
		$size = sizeof($arrHotels);
		$pages = ceil($size / 10);
		for ($i = 0; $i < $pages; $i++) { // Проходим по страницам (10 отелей каждая)
			$arrSliceHotels = Service_ArrayConverter::getArraySlice($arrHotels, $i * 10, 10);
			foreach ($arrSliceHotels as $arrHotel) { // Проходим по отелям
				$result = $objCurl->httpRequest('GET', $arrHotel['url'], null, false);
				$arrResult = array();
				preg_match_all('#no_cc#', $result, $arrResult);
				$isNoCC = 0 + isset($arrResult[0][1]);
				if (!$onlyCheck || ($arrHotel['no_cc'] XOR $isNoCC)) { // Обновляем данные если не проверка или если данные не совпадают
					$stmt = "UPDATE hotel SET no_cc = " . $isNoCC . ", no_cc_check = '" . Service_Date::gLocalTime2BD() . "' WHERE ID_hotel = " . $arrHotel['ID_hotel'];
					$objDB->query($stmt);
				}
				if ($onlyCheck) return $isNoCC;
			}
			$time = Pressure::calculateCurrentDuration();
			if ($time > $timeLimit) { // Если превысили лимит времни, то пора заканчивать
				return true;								
			}
		}
		return false;
	}
	
	/**
	 * Парсинг флеш-дилов
	 * 
	 * @return bool - true означет, что на последующих страницах предполается обнаружить еще гостиницы
	 */
	public function parseFlashDeals() {
		Service_Debug::setDebug();
		$objCurl = new Service_Curl();
		$url = 'http://www.booking.com/searchresults.en-gb.html';
		$objDB = Service_Database::instance();
		//$url = 'http://www.booking.com/hotel/ru/kebu-palace.en-gb.html';
		$arrParams = array(
			'offset' => $this->offset,
			'flash_deals' => 1,
			'rows' => $this->rows,
			'selected_currency' => 'RUB'
		);
		
		$result = $objCurl->httpRequest('GET', $url, $arrParams, false);
		if (!preg_match_all('#id=\"b_hotel_list.*?(<ul>.*?</ul>)#s', $result, $arrMatches)) return false;
		$newStr = $arrMatches[1][0];
		if (!preg_match_all("#(<li)(.*?)(</li>)#s", $newStr, $arrMatches, PREG_PATTERN_ORDER)) return false;
		$arrHotelBlocks = $arrMatches[0];
		$arrCalculatedInfo = array();
		foreach ($arrHotelBlocks as $strHotelBlock) {
			$arrHotelData = array();
			if (!preg_match('#Time left to book:<br \/>\s*([0-9:]*)#s', $strHotelBlock, $arrTimeMatches)) continue;
			if (!preg_match('#<div class=\"b_price_meta b_price\">\s+RUB ([0-9\.]*)#s', $strHotelBlock, $arrPriceMatches)) continue;
			if (!preg_match('#Save up to RUB ([0-9\.]*)#s', $strHotelBlock, $arrPriceSaveMatches)) continue;
			//$str = '<a href="/hotel/ru/kebu-palace.en-gb.html?sid=e5a99d87aadacc3e98ad8638020c3c9f;dcid=1;checkin=2012-06-01;checkout=2012-06-02;srfid=2e37b91f7a1dad983693a577455f2dc3X2" class="jq_tooltip"';
			if (!preg_match('#<a href=\"([a-zA-Z0-9_;\.\?\/\-=]+)\"#s', $strHotelBlock, $arrHotelMatches)) continue;
			$link =  $arrHotelMatches[0];
			preg_match('#<a href=\"([a-zA-Z0-9_;\.\?\/\-=]+)\"#s', $link, $arrUrl);
			preg_match('#/([a-zA-Z0-9_\/\-]+)#s', $link, $arrUrl);
			preg_match('#checkin=([0-9\-]+)#s', $link, $arrDateArr);
			preg_match('#checkout=([0-9\-]+)#s', $link, $arrDateDep);
			$arrHotelData['finish_at'] = $arrTimeMatches[1];
			$arrHotelData['price'] = $arrPriceMatches[1];
			$arrHotelData['save_price'] = $arrPriceSaveMatches[1];
			$arrHotelData['url'] = 'http://www.booking.com/' . $arrUrl[1] . '.html';
			$arrHotelData['date_arr'] = $arrDateArr[1];
			$arrHotelData['date_dep'] = $arrDateDep[1];
			$arrCalculatedInfo[] = $arrHotelData;
		}
		if ($arrCalculatedInfo) {
			$arrUrls = Service_ArrayConverter::getColumn($arrCalculatedInfo, 'url');
			
			$stmt = "SELECT `hotel`.`ID_hotel`, `hotel`.`url`
				 FROM `hotel`
				 INNER JOIN `deal` USING(`ID_hotel`) 
				 WHERE `hotel`.`url` IN ('" . implode("','", $arrUrls) . "') AND `deal`.`finish_at` IS NULL";
			$arrHotelsWithUrls = $objDB->select($stmt);
			$arrCalculatedInfo = Service_ArrayConverter::combineArraysAddFields($arrCalculatedInfo, $arrHotelsWithUrls, 'url', 'url', array('ID_hotel' => 'ID_hotel'));
			$arrToSave = array();
			foreach ($arrCalculatedInfo as $hotelInfo) {
				if (!isset($hotelInfo['ID_hotel'])) continue;
				unset($hotelInfo['url']);
				$arrToSave[] = $hotelInfo;
				$timestamp = time() + substr($hotelInfo['finish_at'], 0, 2) * 3600 + substr($hotelInfo['finish_at'], 3, 2) * 60 + substr($hotelInfo['finish_at'], 5, 2); 
				$stmt = "UPDATE `deal` SET
					`deal`.`price` = '" . $hotelInfo['price'] . "',
					`deal`.`save_price` = '" . $hotelInfo['save_price'] . "',
					`deal`.`date_arr` = '" . $hotelInfo['date_arr'] . "',
					`deal`.`date_dep` = '" . $hotelInfo['date_dep'] . "',
					`deal`.`finish_at` = '" . Service_Date::gLocalTime2BD($timestamp) . "'
					WHERE `deal`.`ID_hotel` = '" . $hotelInfo['ID_hotel'] . "'
				";
				$objDB->query($stmt);
			}
			return $this->rows == sizeof($arrHotelBlocks);
		}
		return true;
			
	}
	/**
	 * Глобальный парсинг отелей, которые можно бронировать без кредитки
	 */
	public function parseAllNoCreditCardHotels() {
		Service_Debug::setDebug();
		set_time_limit(0);
		Pressure::setStart();
		$objDB = Service_Database::instance();
		// Парсим самые популярные города
	  $stmt = "SELECT `hotel_search`.`ID_essence` AS 'ID_city', COUNT(`hotel_search`.`ID_hotel_search`) AS `amount`, TIMESTAMPDIFF(DAY, city.no_cc_check, '" . Service_Date::gLocalTime2BD() . "') AS 'days' 
	  FROM `hotel_search`
	  LEFT JOIN city ON `hotel_search`.`ID_essence` = `city`.`ID_city`
	  WHERE (TO_DAYS(NOW()) - TO_DAYS(`created_at`) <= 60) AND `essence_type` = 7 AND city.nr_hotels > 0
	  GROUP BY `hotel_search`.`ID_essence`
	  ORDER BY `amount` DESC
	  LIMIT 20";
	  $arrPopularCities = $objDB->select($stmt);
	  foreach ($arrPopularCities as $arrPopularCity) {
		  if ($arrPopularCity['days'] >= 1 || $arrPopularCity['days'] === null) {
		    $stop = $this->parseNoCreditCardHotels('city', $arrPopularCity['ID_city']);
		    $this->_updateCityNoCC($arrPopularCity['ID_city']);
				if ($stop) return true;
		  }		  
	  }
	  
	  // Парсим менее популярные города
		$stmt = "SELECT `hotel_search`.`ID_essence` AS 'ID_city', COUNT(`hotel_search`.`ID_hotel_search`) AS `amount`, TIMESTAMPDIFF(DAY, city.no_cc_check, '" . Service_Date::gLocalTime2BD() . "') AS 'days' 
	  FROM `hotel_search`
	  LEFT JOIN city ON `hotel_search`.`ID_essence` = `city`.`ID_city`
	  WHERE (TO_DAYS(NOW()) - TO_DAYS(`created_at`) <= 60) AND `essence_type` = 7 AND city.nr_hotels > 0
	  GROUP BY `hotel_search`.`ID_essence`
	  ORDER BY `amount` DESC
	  LIMIT 20, 100";
	  $arrPopularCities = $objDB->select($stmt); 
	  foreach ($arrPopularCities as $arrPopularCity) {
		  if ($arrPopularCity['days'] >= 4 || $arrPopularCity['days'] === null) {
		    $stop = $this->parseNoCreditCardHotels('city', $arrPopularCity['ID_city']);
		    $this->_updateCityNoCC($arrPopularCity['ID_city']);
				if ($stop) return true;
		  }		
	  }
	  
		// Парсим менее популярные города
		$stmt = "SELECT `hotel_search`.`ID_essence` AS 'ID_city', COUNT(`hotel_search`.`ID_hotel_search`) AS `amount`, TIMESTAMPDIFF(DAY, city.no_cc_check, '" . Service_Date::gLocalTime2BD() . "') AS 'days' 
	  FROM `hotel_search`
	  LEFT JOIN city ON `hotel_search`.`ID_essence` = `city`.`ID_city`
	  WHERE (TO_DAYS(NOW()) - TO_DAYS(`created_at`) <= 120) AND `essence_type` = 7 AND city.nr_hotels > 0
	  GROUP BY `hotel_search`.`ID_essence`
	  ORDER BY `amount` DESC
	  LIMIT 120, 400";
	  $arrPopularCities = $objDB->select($stmt); 
	  foreach ($arrPopularCities as $arrPopularCity) {
		  if ($arrPopularCity['days'] >= 10 || $arrPopularCity['days'] === null) {
		    $stop = $this->parseNoCreditCardHotels('city', $arrPopularCity['ID_city']);
		    $this->_updateCityNoCC($arrPopularCity['ID_city']);
				if ($stop) return true;
		  }		
	  }
	  
	  // Парсим остальные города
		$stmt = "SELECT `city`.`ID_city`, TIMESTAMPDIFF(DAY, city.no_cc_check, '" . Service_Date::gLocalTime2BD() . "') AS 'days' 
	  FROM `city`
	  WHERE 'days' >= 10 OR city.no_cc_check IS NULL AND city.nr_hotels > 0
	  ORDER BY city.no_cc_check, city.nr_hotels DESC
	  LIMIT 10";
		$arrPopularCities = $objDB->select($stmt); 
		foreach ($arrPopularCities as $arrPopularCity) {
	    $stop = $this->parseNoCreditCardHotels('city', $arrPopularCity['ID_city']);
	    $this->_updateCityNoCC($arrPopularCity['ID_city']);
			if ($stop) return true;
	  }				
	}		
	
	/**
	 * Обновляем время парсинга для города, как самое старое время парсинга его отелей
	 * 
	 * @param int $cityId - ID города
	 */
	private function _updateCityNoCC($cityId) {
		Service_Debug::setDebug();
		$objDB = Service_Database::instance();
		$stmt = "SELECT COUNT(ID_hotel) FROM hotel WHERE ID_city = '" . $cityId . "'";
		if (!$objDB->selectSimpleField($stmt)) { // Если нет отелей в городе, то ставим время парсинга сейчас
			$stmt = "UPDATE city SET no_cc_check = '" . Service_Date::gLocalTime2BD() . "' WHERE ID_city = " . $cityId;
		}
		else {
			$stmt = "UPDATE city SET no_cc_check = (
								 SELECT no_cc_check 
								 FROM hotel 
								 WHERE ID_city = " . $cityId . "
								 ORDER BY no_cc_check
								 LIMIT 1
							 )
							 WHERE ID_city = " . $cityId;
		}
		$objDB->query($stmt);
	}
	
	/**
	 * Проверяем статус заказа
	 *
	 * @param int $bookingComId - Идентификатор заказа booking.com
	 * @param int $checkOutFrom - Дата выезда из отеля, начиная с которой идет проверка включительно
	 * @param bool $checkOutUntil - Дата выезда из отеля, до которой идет проверка включительно
	 *
	 * @return array - Массив данных
	 */
	public function getBookingDetails($bookingComId = null, $checkOutFrom = '', $checkOutUntil = '', $beginDate = '', $endDate = '') {
		$arrToSend = array();
		if ($bookingComId) $arrToSend = array('id' => $bookingComId);
		elseif (!empty($checkOutFrom) && !empty($checkOutUntil)) $arrToSend = array('checkout_from' => $checkOutFrom, 'checkout_until' => $checkOutUntil);
		elseif (!empty($beginDate) && !empty($endDate)) $arrToSend = array('begin_date' => $beginDate, 'end_date' => $endDate);
		else return array();
		$arrToSend['rows'] = $this->rows;
		$arrToSend['offset'] = $this->offset;
		$objCurl = new Service_Curl();
		$objCurl->useSSL = true;
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getBookingDetails', 1), $arrToSend);
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Возвращаем комиссию по конкретному бронированию
	 * 
	 * @param Booking $objBooking - Бронирование
	 */
	public function getComission(Booking $objBooking) {
		Service_Debug::setDebug();
		$comission = 0;
		if ($objBooking->getField('payment_type') != 'Another') {
			if ($objBooking->getField('is_our')) { // Получаем коммисию для нашего отеля
				$hotelComission = $objBooking->getField('comission');
				$objHotel = new OurHotel($objBooking->getField('ID_hotel'));
				$currencyCode = $objHotel->getField('currency_code');
			}
			else { // Получаем коммисию для отеля с Букинга
				$arrBookingComDetails = $this->getBookingDetails($objBooking->getField('id'));
				if (isset($arrBookingComDetails[0])) {
					$objBooking->updateByBookingComDetails($arrBookingComDetails[0]);
					$hotelComission = $objBooking->getField('b_com_euro_fee');
					$currencyCode = 'EUR';
				}
			}
			if (!empty($hotelComission)) { 
				// Переводим комиссию в доллары	
				$userCurrency = Service_Exchange::getCurrency();
				Service_Exchange::setCurrency('USD');
				$objExchange = Service_Exchange::instance();
				$comission = $objExchange->getShortPrice($hotelComission, $currencyCode);
				Service_Exchange::setCurrency($userCurrency);
			}
		}		
		if (!$comission) $comission = $objBooking->getBookingPrice('USD') * 0.08;
		return $comission;				
	}
	
	/**
	 * Получаем флэш дилы
	 *
	 * @return array - Массив данных
	 */
	public function getHotelFlashDealCountries() {
		$objCurl = new Service_Curl();
		$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getHotelFlashDealCountries'), array(
			'aid' => 319657, 
		));
		return $this->_processResult($arrResult);
	}
	
	/**
	 * Получаем id отелей, в которых имеются флеш дилы за ближайшие 90 дней
	 * Скрипт выполняется не более 25 секунд
	 */
	public function getHotelAvailabilityFlashDeal() {
		$timeEnd = $timeStart = time();
		$objDeal = new Deal();
		$objDeal->updateDeals(); // Обновляем таблицу дилов
		
		$objDateTime = new DateTime();
		$objDateTime->modify('-1 day');
		
		$arrHotelsDeals = $objDeal->find('all', array('select' => '`ID_hotel`, `ID_deal`, `last_date_parse`', 'order' => '`last_date_parse`'));
		for ($i = 0; $i < count($arrHotelsDeals); $i++)
			if (empty($arrHotelsDeals[$i]['last_date_parse']) || $arrHotelsDeals[$i]['last_date_parse'] < $objDateTime->format('Y-m-d')) {
			$arrHotelsDeals[$i]['last_date_parse'] = $objDateTime->format('Y-m-d');
		}
		$arrHotelsDealsByHotelKeys = Service_ArrayConverter::makeKeyArrayFromMultyArray($arrHotelsDeals, 'ID_hotel');

		$arrDealsDate = array();
		$arrDealsUpdate = array();
		$arrDealsDelete = array();
		$objCurl = new Service_Curl();
		$objDB = Service_Database::instance();
		$botelsInBlockAmount = 50;
		$daysToParseAmount = 90;
		while ($timeEnd - $timeStart < 25) { // Парсинг выполняется более 25 секунд, то выходим из цикла и сохраняем данные в бд
			$indexToStartParse = 0;
			$timeEnd = time(); // Замеряем время
			$arrHotelsDeals = Service_ArrayConverter::sortArray($arrHotelsDeals, 'last_date_parse');
	
			$arrHotelId = array(); // Id отелей, у которых `last_date_parse` минимальна
			foreach ($arrHotelsDeals as $arrHotelDeal)
				if ($arrHotelDeal['last_date_parse'] == $arrHotelsDeals[0]['last_date_parse']) $arrHotelId[] = $arrHotelDeal['ID_hotel'];
				else break;

			$arrHotelsDealsBy50 = array(); // Массив, в значениях которого будет не более 50 id-шников
			$i = 0;
			$j = 0;
			foreach ($arrHotelId as $HotelId) {
				if ($i++ == $botelsInBlockAmount) {
					$j++;
					$i = 1;
				}
				if ($i == 1) $arrHotelsDealsBy50[$j] = $HotelId;
				else $arrHotelsDealsBy50[$j] .= ',' . $HotelId;
			}
			
			// Выбираем дату, по которой будем парсить
			if($arrHotelsDeals[0]['last_date_parse']) {
				$objDateTime = new DateTime($arrHotelsDeals[0]['last_date_parse']);
				$objDateTime->modify('+1 day');
			}
			else $objDateTime = new DateTime();
			$currentDate = $objDateTime->format('Y-m-d');
			$objDateTime->modify('+1 day');
			
			if (Service_Date::dateDiff(date('Y-m-d'), $currentDate, 'd') >= $daysToParseAmount) break; // Если пропарсили более 90 дней, то выходим
			
			$blocksBy50Amount = count($arrHotelsDealsBy50);
			
			// Заполняем последний блок 50 элементов до конца
			$arrUpdateDeals = explode(',', $arrHotelsDealsBy50[$blocksBy50Amount -1]); // Получаем последний элемент массива, где id разбиты по 50
			if(count($arrUpdateDeals) < $botelsInBlockAmount) { // Количество id меньше 50, то заполняем массив значениями из БД за те же числа 
				$stmt = "SELECT `ID_hotel` 
				FROM `deal_availability` 
				WHERE `date` = '" . $currentDate . "' LIMIT " . ($botelsInBlockAmount - count($arrUpdateDeals));
				$arrDealsAvailability = $objDB->selectSimpleArray($stmt);
				foreach ($arrDealsAvailability as $dealAvailability) {
					$arrHotelsDealsBy50[$blocksBy50Amount - 1] .= ',' . $dealAvailability;
				}
			}

			$j = 1;
			foreach ($arrHotelsDealsBy50 as $hotelDealList) {
				echo $objDateTime->format('Y-m-d');
				echo '<br />';
				$arrResult = $objCurl->httpRequest('GET', $this->getBookingPath('getHotelAvailability'), array(
						'affiliate_id' => 319657,
						'show_only_flash_deals' => 1,
						'arrival_date' => $currentDate,
						'departure_date' => $objDateTime->format('Y-m-d'),
						'hotel_ids' => $hotelDealList
				));
				$arrResults = $this->_processResult($arrResult);
				foreach($arrResults as $arrResult) {
					$arrDealsDate[] = array('ID_hotel' => $arrResult['hotel_id'], 'date' => $currentDate); // Копируем спарсенные данные для таблицы deal_availability
				}
				
				$arrHotelDealList = explode(',', $hotelDealList);
				// Обновляем массив $arrHotelsDeals
				for ($i = $indexToStartParse; $i < count($arrHotelsDeals); $i++) {
					if (in_array($arrHotelsDeals[$i]['ID_hotel'], $arrHotelDealList)) {
						$arrHotelsDeals[$i]['last_date_parse'] = $currentDate; // Обновляем массив $arrHotelsDeals
						// Ключи этого массива - id-шники отелей, а значение - время последнего парсинга (после выполнения цикла сохраним данные в таблицу deal)
						$arrDealsUpdate[$arrHotelsDeals[$i]['ID_hotel']] = $currentDate;
					}
					else {
						$indexToStartParse = $i;
						break;
					}
				}
				// Проверяем дилы, которые были проверены ранее и если их нет, то удаляем
				if ($j == $blocksBy50Amount && !empty($hotelDealList)) {
					$hotelDealList = explode(',',$hotelDealList);
					$hotelDealList = array_diff($hotelDealList, Service_ArrayConverter::getColumn($arrResults, 'hotel_id'));
					foreach ($hotelDealList as $hotelId)
						$arrDealsDelete[] = array('ID_hotel' => $hotelId, 'date' => $currentDate);
				}
				$timeEnd = time();
				if ($timeEnd - $timeStart >= 25) break;
				$j++;
			}
		}
		
		// Сохранение данных
		
			if (!empty($arrDealsDate)) {
			// Сохраняем массив в таблицу deal_availability
			$stmt = 'INSERT INTO `deal_availability` (`ID_deal`, `ID_hotel`, `date`)  VALUES ';
			$i = 0;
			foreach ($arrDealsDate as $arrDeal) {
				if ($i++) $stmt .= ',';
				$stmt .= "('" . $arrHotelsDealsByHotelKeys[$arrDeal['ID_hotel']]['ID_deal'] . "', '" . $arrDeal['ID_hotel'] . "', '" . $arrDeal['date'] . "')";
			}
			$objDB->query($stmt);
		}
		
		if (!empty($arrDealsUpdate)) {
			// Обновляем у таблицы deal столбец last_date_parse
			$strSortNums = '';
			foreach ($arrDealsUpdate as $hoteId => $date) {
				$strSortNums .= " WHEN " . $hoteId . " THEN '" . $date . "'";
			}
			$stmt = "UPDATE `deal`
			SET `last_date_parse` = CASE `ID_hotel` " . $strSortNums . " END";
			$objDB->query($stmt);
		}
		
		// Удаляем дилы, которые не прошли перепроверки 
		if (!empty($arrDealsDelete)) {
			$stmt = "DELETE FROM `deal_availability` WHERE ";
			$i = 0;
			foreach ($arrDealsDelete as $arrDealDelete) {
				if ($i++) $stmt .= " OR (`ID_hotel` = " . $arrDealDelete['ID_hotel'] . " AND `date` = '" . $arrDealDelete['date'] . "')";
				else $stmt .= " (`ID_hotel` = " . $arrDealDelete['ID_hotel'] . " AND `date` = '" . $arrDealDelete['date'] . "')";
			}
			$objDB->query($stmt);
		}
		return true;
	}

	  
	/**
	 * Добавляем отель на перепасинг если есть плохие фотки
	 * 
	 * @param int $hotelId - ID отеля
	 */
  public static function badImage($hotelId) {
  	Service_Debug::setDebug();
		if (!$hotelId) return false;
  	$objHotel = new Hotel($hotelId);
  	if (!$objHotel->id) return false;
	  $objDB = Service_Database::instance();
	  $stmt = "INSERT IGNORE INTO changed_hotel (ID_hotel, country_code, is_new, created_at)
	  				 VALUES (" . $objHotel->id . ", '" . $objHotel->getField('country_code') . "', 0, '" . Service_Date::gLocalTime2BD() . "')";
	  $objDB->query($stmt);
	  if (!defined('MAIL_CLASS_DEFINED')) { // Проверка на сервере ли мы
	  	// Сохраняем инфу что был запрос на парсинг по bad Image
			$objDebug = new Debug();
	  	$objDebug->setFields(array('debug_name' => 'Bad Image', 'debug_text' => array('ID_hotel' => $objHotel->id)));
	  	$objDebug->save();
	  }
  }	
	
}
?>